martes, 9 de octubre de 2012

Indices en Ensemble


Cuando en Caché creamos una clase o editamos una clase y añadimos un:

Index NameIDX On Name;

Lo que hacemos es indicarle al planificador de ejecución de SQL de Caché que tome en cuenta una nueva "ruta" para obtener los valores de la clase. Así si la clase es:

Class MyApp.Student Extends %Persistent 
{
 Property Name As %String;
 Property GPA As %Float;

 Index NameIDX On Name;
}

Y ejecutamos una consulta SQL como:

select * from MyApp.Student where Name like 'David'

Entonces el plan de consulta es:

Read index map MyApp.Student.NameIDX, using the given %SQLUPPER(Name), and looping on ID.
For each row:

Read master map MyApp.Student.IDKEY, using the given idkey value. 
Output the row. 

Como podemos observar el planificador va a utilizar un camino que es utilizar en primer lugar el "index map" MyApp.Student.NameIDX. Como su nombre indica es un "map" un mapa o una dirección al camino de búsqueda, ahora bien, está es la parte de definición, luego está la parte de los datos. 

Un indice utiliza de forma estándar el global ^FullClassNameI para almacenar los valores de indexación. Así por ejemplo el global de indexación para la clase anterior es ^MyApp.StudentI

MUY IMPORTANTE: Cuando definimos el indice en la clase y compilamos, a partir de ese momento estamos diciendole al planificador que puede utilizar ese indice pero eso no significa que el indice contenga datos. Si, por ejemplo, tenemos una tabla que dispone de 100 filas y definimos un indice en la clase el planificador inmediatamente lo va a usar pero al usarlo encontrará siempre 0 registros ya que el global de indexación para ese indice estará vacío.

En los casos en los que partimos de una tabla vacía, de manera automática cada vez que se realiza un INSERT (o un %Save()) se añade una entrada al global de indexación. Por ejemplo para la sentencia:

insert into MyApp.Student (Name, GPA) values ('David',95.4)

El global de indexación queda como sigue:

USER>zw ^MyApp.StudentI
^MyApp.StudentI("NameIDX"," DAVID",1)=""

Esto quiere decir que para el valor "DAVID" el ID asociado es el 1.

Si la clase MyApp.Student dispone de 100 filas antes de la creación del indice el global estará vacío y no encontrará a nadie cuando se ejecute una sentencia que utilice el indice. Para poder generar el indice para todas las filas existentes se debe invocar al método %BuilIndices. Este método tiene 3 parámetros, el primero es la lista de indices a generar, si se deja vacío genera todos los indices existentes en la clase. El segundo parámetro indica si se debe borrar las entradas para ese indica en el global previamente a la construcción. El tercer parámetro indice si se debe bloquear el Extent (global) durante la construcción. 

De esta forma podemos tener estas sentencias:

// Genera todos los indices sin borrar los valores anteriores
set tSC=##class(MyApp.Student).%BuildIndices()

// Genera todos los indices borrando los valores anteriores
set tSC=##class(MyApp.Student).%BuildIndices(,1)

// Genera solo el indice "NameIDX" borrando los valores anteriores
set tSC=##class(MyApp.Student).%BuildIndices($lb("NameIDX"),1)

// Genera los indices "NameIDX" y "TestIDX" sin borrar los valores anteriores
set tSC=##class(MyApp.Student).%BuildIndices($lb("NameIDX","TestIDX"))

SIEMPRE se debe consultar el valor devuelto por tSC para comprobar que el indice se ha generado correctamente.

Otra situación posible es que "borremos" o "modifiquemos" un indice. Por ejemplo tenemos el indice:

Index indiceA On campoA;

Y queremos reemplazarlo por el indice:

Index indiceB On (campoA,campoB);

La secuencia correcta sería:

1. Purgar los valores del indice "indiceA" en el global de Indexación
2. Modificar la clase eliminar la definición del "indiceA" y añadir la del "indiceB"
3. Costruir el "indiceB"

Para purgar un indice se utiliza el método %PurgeIndices. Este método dispone de 2 parámetros, el primero es la lista de indices a purgar, si se deja vacío purga todos los indices existentes en la clase. El segundo parámetro indica si se debe bloquear el Extent (global) durante el purgado. 

// Purgar el indice "NameIDX"
set tSC=##class(MyApp.Student).%PurgeIndices($lb("NameIDX"))

Por último, todo esto está bien descrito en este link de la documentación que os pido encarecidamente que leáis:

No hay comentarios: