de Martin LE TARNEC.

Índice Merge


Es una de las preguntas más comunes acerca de la indexación: ¿es mejor crear un índice por cada columna o un único índice con todas las columnas del filtro where? La respuesta es muy sencilla en muchos casos: un índice con múltiples columnas es mejor, es un índice concatenado o compuesto. Índices concatenados lo explica con detalle.

Sin embargo, existen sentencias con las que un solo índice no puede hacer perfectamente el trabajo, sin importar cómo se defina el indice; por ejemplo, sentencias con dos o más condiciones de rangos independientes como el siguiente ejemplo:

SELECT first_name, last_name, date_of_birth 
  FROM employees
 WHERE UPPER(last_name) < ? 
   AND date_of_birth    < ?

Es imposible definir un índice B-tree que pueda soportar esta sentencia sin predicados de filtro. Como explicación, basta recordar que un índice es una lista enlazada.

Si se define un índice como UPPER(LAST_NAME), DATE_OF_BIRTH (en este orden), la lista empieza con A y termina con Z. La fecha de cumpleaños se considera solamente cuando se tienen dos empleados con el mismo apellido. Si se define el índice de forma distinta, éste empezará con el empleado mayor y terminará con el empleado más joven. En este caso, los apellidos sólo tienen un impacto menor sobre el orden del ordenamiento.

Sin importar cómo torcer o girar la definición del índice, las entradas están siempre colocadas a lo largo de la cadena. En el primer borde, tienes las entradas más pequeñas y en el otro borde, las más grandes. Un índice puede, por lo tanto, solamente soportar una condición de rango como acceso predicado. Soportar dos rangos de condiciones independientes necesita un segundo eje, por ejemplo, como un tablero de ajedrez. Entonces, la sentencia siguiente podría coincidir con todas las entradas desde un primer borde del tablero de ajedrez, pero un índice no se parece a un tablero, es más como una cadena. No existen bordes.

Se puede por supuesto aceptar el filtro de predicado y usar sin embargo un índice multi-columna. De todos modos, es la mejor solución en muchos casos. En este caso, la definición del índice deberá mencionar la columna más selectiva primero para usarla como predicado de acceso. Podría ser el origen del mito “de la columna más selectiva primera”, pero esta regla solamente es verdadera si no se puede evitar un filtro de predicado.

La otra alternativa es usar dos índices separados, uno por cada columna. Entonces la base de datos debe primero escanear ambos índices y después mezclar los resultados. Sólo la búsqueda (“LOOKUP”) del índice duplicado implica más esfuerzo porque la base de datos tiene que recorrer los árboles de dos índices. Adicionalmente, la base de datos necesita mucha memoria y tiempo de CPU para mezclar los resultados intermedios.

Nota

El escaneo de un solo índice es más rápido que el de dos.

Las bases de datos utilizan dos métodos para mezclar índices. En primer lugar, existe el JOIN de índices. El Capítulo 4, “La operación de unión (join) explica el algoritmo en detalle. La segunda usa una funcionalidad la cual viene del mundo de almacenes de datos (data warehouse).

El Data warehouse es la madre de todas las sentencias ad hoc. Se necesitan solamente algunos clics para mezclar aleatoriamente condiciones dentro de la sentencia de tu elección. Es imposible pronosticar las combinaciones de columnas que podrían aparecer en el filtro where e indexarlas como se ha explicado hasta ahora es casi imposible.

Los data warehouses usan un tipo de índice especial para resolver ese problema: el llamado indice bitmap. La ventaja de los índices bitmap es que es posible mezclarlos con bastante facilidad. Eso significa que obtienes un rendimiento aceptable cuando se indexa cada columna de manera individual. En cambio, si conoces la sentencia con anticipación, puedes crear un índice multi-columna B-tree a la medida, y será aún más rápido que mezclar múltiples índices bitmap.

De lejos, el mayor punto débil de los índices bitmap es la escalabilidad de los comandos insert, update y delete. Las operaciones de escritura simultáneas son virtualmente imposibles. Eso no supone un problema en los data warehouse porque los procesos de carga se programan uno tras otro. En las aplicaciones en línea, los índices bitmap son prácticamente inútiles.

Importante

Los índices bitmap son prácticamente inútiles para el procesamiento de transacciones en línea (OLTP).

Varios productos de bases de datos ofrecen soluciones híbridas entre los índices B-tree y Bitmap. A falta de un mejor camino de acceso, convierten los resultados de varios escaneos B-tree dentro de estructuras bitmap en memoria. Lo que sí puede combinarse de maneras eficientes. Las estructuras bitmap no se almacenan persistentemente sino que se desechan después de la ejecución de la sentencia; eso soluciona el problema de la pobre escalabilidad en escritura. Este método es, después de todo, un acto desesperado por parte del optimizador.

Si te gusta mi manera de explicar, te encantará mi libro.

Acerca del autor

Foto de Markus Winand

Markus Winand enseña eficientemente SQL, en casa y online. Minimiza el tiempo de desarrollo utilizando moderno SQL y optimiza el tiempo de ejecución con indexación inteligente. Para ello también ha publicado el libro SQL Performance Explained.

“Use The Index, Luke” de Markus Winand se halla bajo licencia Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License.
Aspectos legales | Contacto | SIN GARANTÍA | Marcas | Privacy | CC-BY-NC-ND 3.0 licencia