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 que se pueden ofrecer ante esto son: convertir texto en números, por ej. utilizando autonumber (vea ejemplos de ello en la sección anterior) y/o hacer la comprobación 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 ;

Nota: Tenga presente que la agregación se realiza sobre Alfa ya que ésta es la dimensión que estamos comprobando.

If ( Condition, Sum(‘FieldName’)..)

Esta construcción se incluye aquí sólo 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)

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())))))

leyendo los campos GAC12_STD_COST y GAC15_EXCHANGE_RATE como dimensiones de cambio lento.

Vea: Utilizar la sintaxis ampliada de intervalmatch para resolver problemas de cambios de dimensión progresivos

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 sólo 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 sólo 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.