Оптимизация производительности приложений
Введение
Поскольку приложения QlikView имеют малый и средний размер, обычно можно не беспокоиться о производительности при разработке приложений. По мере увеличения объема данных ограничения по времени и памяти при неправильной структуре приложения могут стать очень очевидными. Часто некоторые простые изменения структуры позволяют существенно повысить производительность. В этом приложении описано несколько подводных камней и рассказано, как их можно избежать.
Общую производительность можно повысить путем переноса «проблемы» из объектов приложений в базу данных, управляемую скриптом. Часто это позволяет спасти ситуацию. Время отклика улучшается, а специальные функции сокращаются. Следующие рекомендации не следует рассматривать как универсально полезные. Их следует использовать. когда они позволяют улучшить состояние приложение или обеспечивают небольшую решающую разницу.
Далее приведен список примеров прикладных методов для решения вышеуказанных проблем. Они позволят продемонстрировать проблему и показать полезные функции QlikView. Невозможно дать какие-то общие рекомендации относительного того, какой из методов является наилучшим, однако можно руководствоваться порядком, в котором перечислены примеры.
If ( Condition(Текст),....)
Операторы If, в которых выполняется сравнение текста, как правило, требуют значительных ресурсов. В качестве решений можно предложить сопоставить текст с числами, например, с помощью функции autonumber (см. примеры в предыдущем разделе), и/или выполнить проверку в скрипте.
Проверка текстовых строк выполняется медленнее, чем проверка числовых значений. Рассмотрим выражение:
If (Alfa= ‘ABC’, ‘ABC’, left (Alfa, 2))
Проверку можно выполнить напрямую в скрипте без потери какой-либо гибкости.
Load
*,
If (Alfa = ‘ABC’, 1, 0) as Flag
resident table_1 ;
Выражение примет следующий вид:
If ( Flag = 1,’ABC’, left (Alfa, 2))
и проверка выполняется с использованием меньшего количества ресурсов.
Sum ( If (Условие, ‘Имя_поля’…))
Здесь агрегация не зависит от измерений таблицы и результат распределяется по измерениям таблицы. Чтобы решить эту проблему, можно либо выполнять проверку в скрипте, а агрегацию в таблице, либо выполнять всю операцию в скрипте. Для этого существует множество способов, например: сопоставление интервалов, group by, peek, if....then....else.
В данном примере используются два этапа, а именно проверка «условия» и агрегация результата. Если мы возьмем предыдущий пример и добавим агрегацию
Sum ( If (Alfa= ‘ABC’, Num*1.25 , Num) )
Load
*,
If (Alfa = ‘ABC’, 1, 0) as Flag
resident table_1 ;
Выражение примет следующий вид:
Sum ( If ( Flag = 1, Num* 1.25 , Num ) )
Агрегацию также можно выполнять напрямую в скрипте следующим образом:
table_2:
Load
*,
If (Alfa = ‘ABC’, 1, 0) as Flag
resident table_1 ;
table_3:
Load
Alfa,
If ( Flag = 1, Num* 1.25 , Num ) as NewNum
resident table_2 ;
table_4:
Load
Alfa,
Sum( NewNum ) as SumNum
resident table_3
group by Alfa ;
If ( Условие, Sum(‘Имя_поля’)..)
Эта конструкция показана здесь только для того, чтобы подчеркнуть различие с предыдущим примером. Эта агрегация полностью является контекстной и, в общем говоря, не вызывает проблем с производительностью.
If ( Условие1, Sum(‘Имя_поля’), If (Условие2, Sum(‘Имя_поля’)……..
Логика конструкции If...then else... концептуально проста, однако часто ее бывает нелегко контролировать. Мы уже видели примеры с сотнями вложенными уровнями. Это требует значительных ресурсов памяти и процессора. «Условия» часто можно заменить путем их трансформирования. Типичным примером является агрегирование выражения количества*цена, где цена представляет собой переменную. Это можно выполнить путем «сопоставления расширенного интервала». Если должны выполняться два условия, например «A И B», то проверку можно заменить условием «C».
Пример:
sum((GAC12_STD_COST * GAC15_EXCHANGE_RATE) * GIV24_DISP_QTY)
Replaces
Sum(
If((GAC12_EFCT_DT<= GIV23_REJ_DT and
GAC12_EXPIRE_DT>GIV23_REJ_DT) and
(GAC15_EFCT_DT<= GIV23_REJ_DT and GAC15_EXPIRE_DT>GIV23_REJ_DT),
GAC12_STD_COST * GAC15_EXCHANGE_RATE) * GIV24_DISP_QTY,
Null()))
and
Sum(
If(GAC12_EFCT_DT<= GIV23_REJ_DT,
If(GAC12_EXPIRE_DT>GIV23_REJ_DT,
If(GAC15_EFCT_DT<= GIV23_REJ_DT,
If(GAC15_EXPIRE_DT>GIV23_REJ_DT,
(GAC12_STD_COST * GAC15_EXCHANGE_RATE) * GIV24_DISP_QTY,
Null())))))
на считывание полей GAC12_STD_COST и GAC15_EXCHANGE_RATE как медленно меняющихся измерений.
Сортировка текста
QlikView автоматически проверяет, следует ли рассматривать поле как числовое значение, текст или общее значение. Поля, которые рассматриваются как текст, будут сортироваться как текст, что является самой медленной операцией сортировки. Ее можно заменить на ручную сортировку по порядку загрузки. Если требуется сортировка списков и т. п., отключите эту функцию.
QlikView выполняет сортировку строк, состоящих их букв и цифр, в алфавитном порядке. Это означает, что числа сортируются по значению, а нечисловые значения сортируются в порядке ASCII, в отличие от традиционного порядка сортировки только по ASCII. Пример:
Сортировка ASCII | Буквенно-цифровая сортировка |
---|---|
A1 | A1 |
A10 | A4 |
A11 | A5 |
A30 | A6 |
A4 | A10 |
A5 | A11 |
A6 | A30 |
Динамические заголовки и текстовые объекты
Динамически вычисляемые выражения можно ввести практически в любом месте, где возможен ввод текста. Однако требуемые ресурсы для оценки выражения зависят от его среды. Выражения в диаграммах и таблицах, которые определены в диалоговом окне выражений, вычисляются только в том случае, когда объект виден и изменяются данные. Например, они не вычисляются при свертывании объекта.
С другой стороны, если вычисляется заголовок объекта, то это вычисление выполняется каждый раз, когда происходит какое-то изменение. Существует множество способов определения условий показа, условий вычислений и т. д. Эти проверки также будут всегда выполняться.
Некоторые выражения являются более ресурсоемкими по сравнению с другими, причем они требуют тем больше ресурсов, тем чаще приходится их вычислять. С появление асинхронного вычисления изменили данное поведение, и, возможно, эти эффекты станут более заметными в ваших приложениях.
Функции времени, например Now() и Today(), будут вычисляться каждый раз, когда требуется повторное вычисление. Особенно функция Now() может требовать значительных ресурсов, поскольку она требует повторного вычисления в приложении каждую секунду.
Например:
If ( ReloadTime()+3>Now(), 'Old Data', 'New Data')
Здесь можно использовать следующий вариант
If ( ReloadTime()+3>Today(), 'Old Data', 'New Data')
В качестве простой проверки поместите выражения в текстовые поля. Затем попробуйте изменить размер текстового поля, когда в нем находится функция Now().
Триггеры макрокоманд («при изменении»)
Можно настроить срабатывание макросов практически на любое событие, происходящее в приложении. Остерегайтесь каскадных или рекурсивных событий, когда одно событие порождает другое, а то в свою очередь первое.