El uso de los índices en una tabla es una forma común de disminuir el tiempo de respuesta de una consulta, y estos índices existen en todos los motores de bases de datos relacionales; sin embargo, en SQL Server existen algunas variantes o tipos de índices que no existen necesariamente en otros motores de bases de datos (como ya se vió con los índices agrupados o cluster) y hoy exploraremos los índices con campos incluidos.
Para poder entender este tipo nuevo de índice revisaremos con detenimiento cómo funcionan los índices regulares y luego veremos la pequeña-gran diferencia con un índices con campos incluidos y, sobre todo, veremos cómo se pueden crear con la instrucción SQL correspondiente.
Como trabaja un índice tradicional
Como se vió en el artículo sobre el tema, un índice es una estructura adicional a la tabla de datos que permite acceder a la tabla de manera más rápida cuando se hace por medio de la clave o llave que forma el índice. Por ejemplo, cuando se tiene una tabla de alumnos con ID, nombre, apellidos, sexo y turno, podemos ver la tabla de datos y el índice como estructuras de la siguiente manera.
Este ejemplo es de un índice por nombre (la llave) que está en un árbol (una estructura adicional a los datos) y la tabla de datos propiamente dicha. De esta manera, si se ejecuta el siguiente SELECT
SELECT con diferentes campos de una tabla
SELECT nombre, apellido
FROM tabla
WHERE nombre='Juan';
El motor de bases de datos utiliza el índice por nombre ejecutando lo siguiente
Busca dentro del índice (el árbol) un nodo que corresponda con el nombre buscado (en este caso es ‘Juan’).
Una vez encontrado el nodo (donde solo está el nombre y un «apuntador» al registro que contiene los datos de Juan) utiliza la información en el nodo para ubicar el registro de la tabla y hace una segunda lectura del registro correspondiente.
Con el nombre que obtuvo del índice, más el Apellido que obtuvo de los datos puede responder el query y regresa los 2 campos requeridos (nombre y apellido).
En este caso la búsqueda es más eficiente que hacerla sin el índice (por que tendría que hacer un barrido secuencial de toda la tabla para encontrar los registros que tengan ‘Juan’ en el nombre, pero tiene que hacer el salto del punto 2 (llamado lookup en el plan de ejecución) para poder responder el query que requería de 2 campos.
¿Qué pasa si la consulta solo necesita del nombre y apellido?
SELECT con dos campos de la tabla
Si un usuario quiera ejecutar un query y solo necesita el nombre y el apellido, tendría que escribir el siguiente query
SELECT nombre, apellido
FROM tabla
WHERE nombre='Juan';
En este caso SQL Server se tiene que hacer el mismo procedimiento, ya que necesita de hacer el «salto» a los datos una vez que encuentra el registro en el índice.
¿Y si existiera una forma de ahorrarse ese salto?
Existe, y en este caso se trata de los índices con campos incluidos.
Un índice con campos incluidos lo que hace es que añade a cada nodo del árbol del índice los campos que nosotros queramos, pero sin formar parte de la llave, solo son datos adicionales. En ese sentido es un índice intermedio entre los índices cluster y los no cluster, ya que el índice contiene datos adicionales a la llave. El índice se podría ver de la siguiente manera.
De esta manera, cuando se ejecuta el código
SELECT nombre, apellido
FROM tabla
WHERE nombre='Juan';
Ya no es necesario es salto a la tabla de datos, ya que toda la información que se necesita para responder la petición ya se tiene dentro del índice. Es por eso que el uso de SELECT * es tan penalizado en el performance, ya que siempre obliga a hacer el lookup a la tabla de datos, y siempre se deberá preferir un SELECT con la enumeración de los campos requeridos por si existiese un índice que pudiera evitar esa lectura adicional.
Ventajas y desventajas de los índices con campos incluidos
Ventaja:
Existe un ahorro de tiempo de procesamiento, ya no hay que leer el índice y después hacer el salto a la tabla de datos.
Desventaja
El índice ocupa ahora más espacio (el campo o los campos incluidos se duplicarán, ya que están en la tabla de datos y en el índice).
Un índice de este tipo es recomendado cuando existen muchas consultas que solo requieren algunos datos -pocos- adicionales a los que tiene la llave y vale la pena la duplicidad de datos por la ganancia en tiempo de procesamiento.
Cláusula INCLUDE en el CREATE INDEX
Para poder crear un índice con campos incluídos solo es necesario incluir la cláusula INCLUDE en el CREATE INDEX. Por ejemplo, para el índice por nombre -incluyendo el apellido- la instrucción podría ser algo como
CREATE INDEX nombreIndice ON tabla (nombre) INCLUDE (apelllido);
Recomendaciones para el uso de índices con campos incluidos
- Los campos incluidos pueden ser de cualquier tipo de datos, excepto text, ntext e image.
- No se podrán eliminar campos -de la estructura de la tabla- cuando dichos campos estén especificados en la cláusula INCLUDE de al menos un índice de campos incluidos.
- Si se quieren cambiar las características de un campo incluido, solo se podrá hacer de tamaño (para los tipos varchar, nvarchar o varbinary) o de NOT NULL a NULL.
- Solo se pueden definir campos incluidos en índices que no son cluster (no tendría sentido ya que los índices cluster o agrupados contienen todos los datos en la estructura del índice).
- Mantener el tamaño del índice como en todos los demás (16 campos y 900 bytes como máximo para versiones anteriores a SQL Server 2016 o de 1,700 bytes y 32 campos para versiones recientes)
Conclusiones
Usarlos o no usarlos en más bien una prerrogativa del DBA o del desarrollador, siempre ponderando la ventaja de disminuir los tiempos de consulta, sobre el aumento del espacio en disco para guardar el índice, la duplicidad de los datos y el tiempo de procesamiento al actualizar dichos índices