Эффективные конструкции языка – оператор ASSIGN
Обычно оптимизация кода приложения, не связанного с доступом к данным, дает меньший эффект с точки зрения производительности, чем оптимизация запросов к базе данных.
Тем не менее, пренебрегать такой оптимизацией не следует.
Рассмотренные далее конструкции языка, при всей их простоте, могут обеспечить значительное улучшение производительности приложения.
Использование ASSIGN
Оператор ASSIGN позволяет сгруппировать несколько идущих подряд операций присвоения значений переменным или полям записей в один оператор ABL.
То, что оператор ASSIGN работает быстрее, чем несколько отдельных операторов присваивания – факт широко известный. Тем не менее, этой простой возможностью улучшить производительность программ очень часто пренебрегают.
Выполненные на версии 10.2B тесты (Программа 64) показывают, что скорость возрастает на 12% при группировке двух операторов присваивания, и на 32% – при группировке 10 операторов.
Программа 64. Оператор ASSIGN
/* Тест производительности оператора ASSIGN */ /* Последовательные присвоения – уберите ASSIGN и */ /* вставьте точки после каждого присваивания */ /* В тесте для двух присваиваний присваивались значения a01 и a10 */ DEFINE VARIABLE i AS INTEGER NO-UNDO. DEFINE VARIABLE a01 AS INTEGER NO-UNDO. DEFINE VARIABLE a02 AS INTEGER NO-UNDO. DEFINE VARIABLE a03 AS INTEGER NO-UNDO. DEFINE VARIABLE a04 AS INTEGER NO-UNDO. DEFINE VARIABLE a05 AS INTEGER NO-UNDO. DEFINE VARIABLE a06 AS INTEGER NO-UNDO. DEFINE VARIABLE a07 AS INTEGER NO-UNDO. DEFINE VARIABLE a08 AS INTEGER NO-UNDO. DEFINE VARIABLE a09 AS INTEGER NO-UNDO. DEFINE VARIABLE a10 AS INTEGER NO-UNDO. ETIME(TRUE). DO i = 1 TO 1000000: ASSIGN a01 = i a02 = i + 1 a03 = i + 2 a04 = i + 3 a05 = i + 4 a06 = i + 5 a07 = i + 6 a08 = i + 7 a09 = i + 8 a10 = i + 9. END. MESSAGE ETIME VIEW-AS ALERT-BOX.
Таким образом, выигрыш может быть весьма существенным, особенно в программах обработки большого числа записей. Так, если выполнить указанный тест для десяти присваиваний в цикле миллион раз, то разница составит ощутимые пол секунды, может быть те самые, которые переполняют чашу терпения пользователя Вашего приложения.
ASSIGN и индексы
Еще один известный факт – ABL выполняет обновление индекса в базе данных немедленно после его изменения в программе. Если индекс многокомпонентный, то есть включает несколько полей, изменение каждого компонента приводит к изменению индекса в базе данных, то есть к выполнению операции ввода-вывода.
Для изменения нескольких компонентов многокомпонентного индекса следует использовать оператор ASSIGN. Это обеспечит увеличение производительности не только за счет эффекта группировки, но и за счет сокращения числа обращений к базе данных для изменения индекса.
Тестовая программа (Программа 65) выполнялась в двух вариантах: изменение двух компонентов индекса последовательно и с помощью ASSIGN. Программа читает единственную запись таблицы customer и затем выполняет цикл присвоения значений 10 тысяч раз. Функция ETIME выдает время исполнения цикла (в миллисекундах), по окончании цикла вызывается программа indexstat.p (смотри Программа 61) для анализа статистики использования индексов.
Результаты тестов показывают увеличение производительности при использовании ASSIGN от 80 до 90%, то есть практически вдвое. Анализ статистики использования индексов показывает, что в случае использования ASSIGN изменение индекса выполнялось 10 тысяч раз, а при последовательном присвоении – 20 тысяч раз.
Следует отметить, что при изменении индекса фактически выполняется два обращения к базе данных – старый индекс удаляется, а новый – создается.
При одновременном изменении большего числа компонентов индекса, скажем, трех, следует ожидать пропорционального увеличения производительности.
Программа 65. Тест оператора ASSIGN для компонентов индекса
/* Тест оператора ASSIGN для компонентов индекса */ DEFINE VARIABLE i AS INTEGER NO-UNDO. DEFINE VARIABLE k AS INTEGER NO-UNDO. FUNCTION kk RETURNS CHAR: k = - k. RETURN STRING(k). END. FOR FIRST customer WHERE custnum = 3030. k = 1. ETIME(TRUE). DO i = 1 TO 10000: ASSIGN country = 'AAA' + kk() /* Вариант 2 */ /* Вариант 1 – простое присвоение, закомментирован */ /* country = 'AAA' + k k = - k. */ city = 'B' + STRING(i) /* Вариант А – присвоение поля */ /* Вариант В – поле city не присваивается */ postalCode = "A" + STRING (i) . END. END. MESSAGE ETIME VIEW-AS ALERT-BOX. RUN indexstat.p.