Optimización del Rendimiento de Aplicaciones
Introducción
Con aplicaciones QlikView de tamaño pequeño o mediano, por lo general no tendrá que preocuparse en exceso del diseño de la aplicación para un buen rendimiento. Pero a medida que aumenta la cantidad de datos, las limitaciones tanto de tiempo como de memoria pueden hacerse demasiado evidentes si la aplicación está mal diseñada. Es posible que unas breves modificaciones en el diseño alteren de forma sustancial el rendimiento. Este apéndice trata de señalar unos cuantos focos de problemas habituales y sugiere sus correspondientes remedios.
Por lo general, el rendimiento mejora trasladando el "problema" de los objetos de la aplicación al script de la base de datos. Esto a menudo se debe evaluar según compense más en cada situación concreta. Los tiempos de respuesta mejoran y la capacidad ad hoc disminuye. Las recomendaciones que siguen a continuación no deberían verse como universalmente beneficiosas. Úselas cuando vea que mejoran el estado general de la aplicación o cuando note que aportan ese pequeño extra de diferencia.
Lo que viene a continuación es una lista con ejemplos prácticos de métodos aplicados para el manejo de los problemas anteriormente mencionados. Sirven de ilustración a problemas comunes y también destacan la utilidad de diversa funcionalidad QlikView. No es posible dar una recomendación general sobre qué método resulta mejor, pero el orden que siguen los ejemplos sí puede servir de indicación.
If ( Condition(Text),....)
Las cláusulas if que implican comparaciones de texto son generalmente muy costosas. Las soluciones pueden ser asignar correspondencias de texto a números, por ejemplo, usando autonumber (ver ejemplos en la sección anterior) y/o hacer la prueba en el script.
La verificación de las cadenas de texto resulta un proceso más lento que las comprobaciones numéricas. Si consideramos la expresión:
If (Alfa= ‘ABC’, ‘ABC’, left (Alfa, 2))
La comprobación podría realizarse directamente en el script sin perder flexibilidad alguna en absoluto.
Load
*,
If (Alfa = ‘ABC’, 1, 0) as Flag
resident table_1 ;
La expresión quedaría:
If ( Flag = 1,’ABC’, left (Alfa, 2))
Y la comprobación resulta mucho más fácil.
Sum ( If (Condition, 'FieldName'…))
En este caso la agregación es independiente de las dimensiones de la tabla y el resultado se distribuye entonces por las dimensiones de la tabla. El problema se puede resolver, bien realizando la comprobación en el script y agregando en la tabla, o bien realizando toda la operación en el script. Para esto existen numerosas técnicas, por ej. interval match, group by, peek, if....then....else.
Este caso implica dos pasos: la comprobación de la "Condición" y la agregación del resultado. Si tomamos el ejemplo anterior y añadimos la agregación
Sum ( If (Alfa= ‘ABC’, Num*1.25 , Num) )
Load
*,
If (Alfa = ‘ABC’, 1, 0) as Flag
resident table_1 ;
La expresión quedaría
Sum ( If ( Flag = 1, Num* 1.25 , Num ) )
La agregación también puede hacerse directamente en el script de la siguiente manera:
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 ( Condition, Sum(‘FieldName’)..)
Esta construcción se incluye aquí solo con el propósito de recalcar la diferencia con el caso anterior. Aquí la agregación es completamente contextual y por lo general no ocasiona problema alguno en cuanto al rendimiento.
If ( Condition1, Sum('FieldName'), If (Condition2, Sum('FieldName')……..
La lógica de If..then else.. anidada es un concepto fácil de entender, pero a menudo difícil de administrar. Hemos visto casos con cientos de niveles de anidación. Esto consume mucha memoria y también mucha CPU. Las "Condiciones" a menudo pueden reemplazarse transformándolas. Un ejemplo típico consiste en agregar cantidad*precio donde "precio" es variable. Esto se puede manejar con "extended interval match". Si dos condiciones, por ej “A y B” han de ser satisfechas, la comprobación puede ser sustituida por una condición “C“.
Ejemplo:
sum((GAC12_STD_COST * GAC15_EXCHANGE_RATE) * GIV24_DISP_QTY)
Reemplaza a
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()))
y
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())))))
leyendo los campos GAC12_STD_COST y GAC15_EXCHANGE_RATE como dimensiones de cambio lento.
Clasificar texto
QlikView evalúa automáticamente si un Campo va a ser tratado como numérico, de texto o general. Los campos evaluados como texto se clasificarán como de texto, lo cual supone la operación de ordenación más lenta. Esto puede también reemplazarse manualmente para que se clasifique por orden de carga. Deshabilite la ordenación de cuadros de lista si no la va a necesitar.
QlikView ordena cadenas de caracteres y números combinados por orden alfanumérico. Es decir, que los números se ordenan según sus valores mientras que los caracteres no numéricos se ordenan por orden ASCII, a diferencia de la ordenación tradicional que era solo de ASCII. Ejemplo:
Ordenación ASCII | Ordenación Alfanumérica |
---|---|
A1 | A1 |
A10 | A4 |
A11 | A5 |
A30 | A6 |
A4 | A10 |
A5 | A11 |
A6 | A30 |
Títulos dinámicos y objetos de texto
Las expresiones calculadas dinámicamente pueden introducirse prácticamente en cualquier parte en la que se pueda introducir texto. Los recursos que se necesitan para evaluar una expresión son sin embargo dependientes de su contexto. Las expresiones en los gráficos y tablas que vienen definidos en el diálogo de las expresiones solo se calculan cuando el objeto es visible y los datos cambian. Por ej. no se calculan cuando el objeto está minimizado.
Por otra parte, si se calcula el título del objeto, dicho cálculo se realizará cada vez que se produzca un cambio. Hay también numerosas maneras de definir condiciones de presentación, condiciones de cálculo, etc. Estas comprobaciones también se realizarán en todas las ocasiones.
Algunas expresiones consumen más que otras y por supuesto resultarán más costosas cuanto más frecuentemente hayan de ser evaluadas. La introducción del cálculo asíncrono ha modificado su comportamiento y estos efectos puede que se hayan hecho más notables en sus aplicaciones.
Las funciones de tiempo, por ej. Now() y Today() se evaluarán cada vez que haya que volver a recalcular. La función Now() en particular puede resultar muy costosa, ya que hace que la aplicación recalcule a cada segundo.
Por ejemplo:
If ( ReloadTime()+3>Now(), 'Old Data', 'New Data')
Aquí se podría considerar
If ( ReloadTime()+3>Today(), 'Old Data', 'New Data')
Simplemente a modo de prueba, ponga la expresión en cuadros de texto. Luego trate de dimensionar el cuadro de texto con Now() en él.
Disparadores de Macros ( "ante cambio" )
Se pueden configurar macros que se disparen prácticamente ante cualquier evento que se produzca en la aplicación. Tenga especial cuidado con los eventos recursivos o en cascada, en los que un evento dispara el siguiente, el cual a su vez dispara otro y así sucesivamente.