¿Qué tan importante es el orden de las columnas en los índices?

173

He oído que debe colocar columnas que serán las más selectivas al comienzo de la declaración de índice. Ejemplo:

CREATE NONCLUSTERED INDEX MyINDX on Table1
(
   MostSelective,
   SecondMost,
   Least
)

En primer lugar, ¿lo que digo es correcto? Si es así, ¿es probable que vea grandes diferencias en el rendimiento al reorganizar el orden de las columnas en mi índice o es más una práctica "agradable de hacer"?

La razón por la que pregunto es porque después de realizar una consulta a través del DTA, recomendó que creara un índice que tuviera casi todas las mismas columnas que un índice existente, solo en un orden diferente. Estaba considerando agregar las columnas que faltaban al índice existente y llamarlo bueno. Pensamientos?

Abe Miessler
fuente

Respuestas:

193

Mira un índice como este:

Cols
  1   2   3
-------------
|   | 1 |   |
| A |---|   |
|   | 2 |   |
|---|---|   |
|   |   |   |
|   | 1 | 9 |
| B |   |   |
|   |---|   |
|   | 2 |   |
|   |---|   |
|   | 3 |   |
|---|---|   |

¿Ves cómo restringir en A primero, ya que tu primera columna elimina más resultados que restringir en tu segunda columna primero? Es más fácil si imagina cómo debe atravesar el índice, la columna 1, luego la columna 2, etc., verá que cortar la mayoría de los resultados en el primer pase hace que el segundo paso sea mucho más rápido.

Otro caso, si realizó una consulta en la columna 3, el optimizador ni siquiera usaría el índice, ya que no es útil para reducir los conjuntos de resultados. Cada vez que esté en una consulta, reducir el número de resultados a tratar antes del siguiente paso significa un mejor rendimiento.

Dado que el índice también se almacena de esta manera, no hay retroceso en todo el índice para encontrar la primera columna cuando se consulta en él.

En resumen: no, no es para mostrar, hay beneficios reales de rendimiento.

Nick Craver
fuente
13
En la imagen de arriba, tenga en cuenta que ese índice solo sería beneficioso si se especificara la Columna 1 en la consulta. Si su consulta solo especifica la Columna 2 en el Predicado Unir o Buscar, entonces no sería beneficioso. Entonces el orden también importa allí. Tal vez eso sea evidente, pero quería mencionarlo.
CodeCowboyOrg
3
También tenga en cuenta, suponga que su índice es como la imagen de arriba, y su consulta se filtra en la columna1 y la columna2, pero la columna2 es más única y lo que realmente desea filtrar es en realidad la columna2, entonces es más beneficioso tener un índice donde la columna 2 es la primera. Esto puede parecer contradictorio, pero tenga en cuenta que un índice se almacena en varias páginas y es un árbol con un rango de valores, mientras que la Columna 1 anterior niega la mitad de las posibilidades, el índice ya sabe a qué página de índice ir directamente para Columna2, no es necesario que la Columna 1 limite el conjunto.
CodeCowboyOrg
44
Esta imagen no es una representación precisa de cómo se estructuran o navegan los índices. Han enviado una respuesta rectificando este stackoverflow.com/a/39080819/73226
Martin Smith
66
@ MartinSmith No estoy de acuerdo con que sea inexacto. Es, sin duda, extremadamente simplificado, que era mi intención. Sin embargo, se agradece su respuesta profundizando mucho más en los niveles, para aquellos que quieran profundizar en ella. Si miras la imagen de tu árbol, verás lo que estoy ilustrando de una manera muy simple. Esto no es muy único o incluso específico de SQL; La indexación del árbol B es bastante común en muchas cosas.
Nick Craver
@ MartininSmith tampoco estoy de acuerdo con que sea inexacto, lo que está describiendo es el comportamiento estándar de cómo llegar al índice de cobertura: la selectividad es mucho más importante una vez que realiza consultas de rango, ya que esto minimiza el número de páginas de índice que el optimizador debe escanear; esto puede ser significativo en tablas grandes con millones de filas
Paul Hatcher
127

El orden de las columnas es crítico. Ahora, qué orden es correcto, depende de cómo va a consultarlo. Se puede usar un índice para hacer una búsqueda exacta o un escaneo de rango. Una búsqueda exacta es cuando se especifican valores para todas las columnas del índice y la consulta aterriza exactamente en la fila que le interesa. Para las búsquedas, el orden de las columnas es irrelevante. Una exploración de rango es cuando solo se especifican algunas columnas, y en este caso cuando el orden se vuelve importante. SQL Server puede usar un índice para una exploración de rango solo si se especifica la columna más a la izquierda, y luego solo si se especifica la siguiente columna a la izquierda, y así sucesivamente. Si tiene un índice en (A, B, C) puede usarse para escanear el rango para A=@a, A=@a AND B=@bpero no para B=@b, para C=@cni B=@b AND C=@c. El caso A=@a AND C=@ces mixto, como en elA=@ala porción usará el índice, pero C=@cno (la consulta escaneará todos los valores de B A=@a, no 'saltará' a C=@c). Otros sistemas de bases de datos tienen el llamado operador 'omitir exploración' que puede aprovechar algunas de las columnas internas de un índice cuando no se especifican las columnas externas.

Con ese conocimiento en la mano, puede volver a ver las definiciones de índice. Un índice (MostSelective, SecondMost, Least)activado solo será efectivo cuando MostSelectivese especifique la columna. Pero al ser el más selectivo, la relevancia de las columnas internas se degradará rápidamente. Muy a menudo encontrará que un mejor índice está activado (MostSelective) include (SecondMost, Least)o activado (MostSelective, SecondMost) include (Least). Debido a que las columnas internas son menos relevantes, colocar columnas de baja selectividad en esas posiciones correctas en el índice no hace más que ruido para una búsqueda, por lo que tiene sentido moverlas fuera de las páginas intermedias y mantenerlas solo en las páginas de hoja, para fines de cobertura de consultas. En otras palabras, muévalos para INCLUIR. Esto se vuelve más importante a medida que aumenta el tamaño de la Leastcolumna. La idea es que este índice solo pueda beneficiar consultas que especifiquenMostSelective ya sea como un valor exacto o un rango, y esa columna es la más selectiva, ya restringe las filas candidatas en gran medida.

Por otro lado, un índice (Least, SecondMost, MostSelective)puede parecer un error, pero en realidad es un índice bastante poderoso. Debido a que tiene la Leastcolumna como su consulta más externa, se puede usar para consultas que tienen que agregar resultados en columnas de baja selectividad. Dichas consultas son frecuentes en los almacenes de datos de análisis y OLAP, y aquí es exactamente donde tales índices tienen un muy buen caso para ellos. Dichos índices en realidad son excelentes índices agrupados , exactamente porque organizan el diseño físico en grandes fragmentos de filas relacionadas (el mismo Leastvalor, que generalmente indica algún tipo de categoría o tipo) y facilitan las consultas de análisis.

Entonces, desafortunadamente, no hay un orden 'correcto'. No debe seguir ninguna receta de cortador de galletas, sino analizar el patrón de consulta que va a utilizar en esas tablas y decidir qué orden de columna de índice es el correcto.

Remus Rusanu
fuente
3
Impresionante respuesta como siempre Remus. Voy a leer su tercer párrafo unas cuantas veces más y seguiré. Sospecho que eso puede ser exactamente lo que necesito hacer.
Abe Miessler
"SQL Server puede usar un índice para una exploración de rango solo si se especifica la columna más a la izquierda, y luego solo si se especifica la siguiente columna a la izquierda, y así sucesivamente". Esto es exactamente lo que me faltaba, ¡gracias! No sabía que los escaneos de rango solo se pueden hacer en la columna de índice utilizada más a la derecha, pero ahora que lo hago tiene mucho sentido.
Allon Guralnek
¿Es esta explicación aplicable para Oracle DB?
otro
1
@Roizpi Sí, básicamente, cualquier base de datos de relaciones con índices funciona de la misma manera o de manera muy similar.
Tatranskymedved
45

Como dice Remus, depende de tu carga de trabajo.

Sin embargo, quiero abordar un aspecto engañoso de la respuesta aceptada.

Para las consultas que realizan una búsqueda de igualdad en todas las columnas del índice, no existe una diferencia significativa.

Lo siguiente crea dos tablas y las completa con datos idénticos. La única diferencia es que una tiene las claves ordenadas de la más selectiva a la menos selectiva y la otra al revés.

CREATE TABLE Table1(MostSelective char(800), SecondMost TINYINT, Least  CHAR(1), Filler CHAR(4000) null);
CREATE TABLE Table2(MostSelective char(800), SecondMost TINYINT, Least  CHAR(1), Filler CHAR(4000) null);

CREATE NONCLUSTERED INDEX MyINDX on Table1(MostSelective,SecondMost,Least);
CREATE NONCLUSTERED INDEX MyINDX2 on Table2(Least,SecondMost,MostSelective);

INSERT INTO Table1 (MostSelective, SecondMost, Least)
output inserted.* into Table2
SELECT TOP 26 REPLICATE(CHAR(number + 65),800), number/5, '~'
FROM master..spt_values
WHERE type = 'P' AND number >= 0
ORDER BY number;

Ahora haciendo una consulta en ambas tablas ...

SELECT *
FROM   Table1
WHERE  MostSelective = REPLICATE('P', 800)
       AND SecondMost = 3
       AND Least = '~';

SELECT *
FROM   Table2
WHERE  MostSelective = REPLICATE('P', 800)
       AND SecondMost = 3
       AND Least = '~'; 

... Ambos usan una multa de índice y ambos reciben exactamente el mismo costo.

ingrese la descripción de la imagen aquí

El arte ASCII en la respuesta aceptada no es, de hecho, cómo se estructuran los índices. Las páginas de índice para la Tabla 1 se representan a continuación (haga clic en la imagen para abrirla a tamaño completo).

ingrese la descripción de la imagen aquí

Las páginas de índice contienen filas que contienen la clave completa (en este caso, en realidad hay una columna de clave adicional agregada para el identificador de fila, ya que el índice no se declaró como único, pero se puede descartar más información al respecto aquí ).

Para la consulta anterior, a SQL Server no le importa la selectividad de las columnas. Realiza una búsqueda binaria de la página raíz y descubre que la clave (PPP...,3,~ ) es >=(JJJ...,1,~ )y, < (SSS...,3,~ )por lo tanto, debe leer la página 1:118. Luego realiza una búsqueda binaria de las entradas clave en esa página y localiza la página de hoja para viajar hacia abajo.

La alteración del índice en orden de selectividad no afecta ni el número esperado de comparaciones clave de la búsqueda binaria ni el número de páginas que se deben navegar para realizar una búsqueda de índice. En el mejor de los casos, podría acelerar marginalmente la comparación de claves en sí.

Sin embargo, a veces ordenar primero el índice más selectivo tendrá sentido para otras consultas en su carga de trabajo.

Por ejemplo, si la carga de trabajo contiene consultas de las dos formas siguientes.

SELECT * ... WHERE  MostSelective = 'P'

SELECT * ...WHERE Least = '~'

Los índices anteriores no cubren ninguno de ellos. MostSelectivees lo suficientemente selectivo como para hacer que un plan con una búsqueda y búsquedas valga la pena, pero la consulta en contra Leastno lo es.

Sin embargo, este escenario (búsqueda de índice no cubriente en el subconjunto de columnas principales de un índice compuesto) es solo una posible clase de consulta que puede ser ayudada por un índice. Si nunca buscas realmente porMostSelective sí solo o una combinación de MostSelective, SecondMosty siempre busca por una combinación de las tres columnas, esta ventaja teórica es inútil para usted.

Por el contrario, consultas como

SELECT MostSelective,
       SecondMost,
       Least
FROM   Table2
WHERE  Least = '~'
ORDER  BY SecondMost,
          MostSelective 

Sería útil contar con el orden inverso al comúnmente recetado, ya que cubre la consulta, puede admitir una búsqueda y devuelve filas en el orden deseado para arrancar.

Por lo tanto, este es un consejo que se repite a menudo, pero a lo sumo es una heurística sobre el beneficio potencial de otras consultas, y no es un sustituto para analizar realmente su carga de trabajo.

Martin Smith
fuente
31

debe colocar columnas que serán las más selectivas al comienzo de la declaración de índice.

Correcto. Los índices pueden ser compuestos, compuestos de múltiples columnas, y el orden es importante debido al principio más a la izquierda. La razón es que la base de datos verifica la lista de izquierda a derecha y tiene que encontrar una referencia de columna correspondiente que coincida con el orden definido. Por ejemplo, tener un índice en una tabla de direcciones con columnas:

  • Habla a
  • Ciudad
  • Estado

Cualquier consulta que use la addresscolumna puede utilizar el índice, pero si la consulta solo tiene referencias cityy / o statereferencias, el índice no se puede usar. Esto se debe a que la columna de la izquierda no está referenciada. El rendimiento de la consulta debe indicar cuál es el óptimo: índices individuales o múltiples compuestos con diferentes órdenes. Buena lectura: The Tipping Point , de Kimberley Tripp

Ponis OMG
fuente
¿Qué pasaría si solo se usara la columna de la derecha? Entonces, una consulta usó Dirección y ciudad, pero NO estado. ¿Se usaría el índice entonces?
Abe Miessler
@Abe: No se usaría el extremo derecho; debe satisfacer el orden del índice comenzando por el izquierdo. Señorita uno, no puedo usarlo.
OMG Ponies
44
@Abe: Si realizó una consulta en Dirección y ciudad, pero NO en estado, entonces sí, se usaría el índice. En otras palabras, la base de datos puede usar índices parciales para satisfacer una solicitud, siempre que pueda comenzar desde la izquierda de un índice y moverse hacia la derecha al usar los campos que se están consultando. Sin embargo, si realizó una consulta usando Dirección y Estado, pero NO ciudad, aún puede usar el índice, pero no será tan eficiente, porque ahora solo puede usar la porción de Dirección del índice (b / c siguiente es ciudad y no se está utilizando en la consulta).
JaredC
6

Todas las otras respuestas son incorrectas.

La selectividad de las columnas individuales en un índice compuesto no importa al elegir el orden.

Aquí está el proceso de pensamiento simple: efectivamente, un índice es la concatenación de las columnas involucradas.

Dando esa razón, la única diferencia es comparar dos 'cadenas' que difieren más temprano que más tarde en la cadena. Esta es una pequeña parte del costo total. No hay "primer pase / segundo pase", como se menciona en una respuesta.

Entonces, ¿qué orden se debe usar?

  1. Comience con las columnas probadas con =, en cualquier orden.
  2. Luego agregue una columna de rango.

Por ejemplo, la columna de selectividad muy baja debe venir primero en esto:

WHERE deleted = 0  AND  the_datetime > NOW() - INTERVAL 7 DAY
INDEX(deleted, the_datetime)

Cambiar el orden en el índice lo ignoraría por completo deleted.

(Hay muchas más reglas para ordenar las columnas).

Rick James
fuente
¿Es el voto negativo porque estoy equivocado? ¿O porque tengo una opinión fuerte? ¿O algo mas?
Rick James
¿no fue mi voto negativo, pero eliminado = 0 para mí suena como si no fuera baja selectividad? Me imagino que sería la mayoría de las filas en la tabla.
Greg
@ Greg - Creo que eso significa "baja selectividad" - Es decir, el uso deletedno ayuda mucho a filtrar las filas no deseadas. ¿Tienes un mejor ejemplo? (Esa fue la que me vino a la mente cuando escribí la respuesta.)
Rick James,
Malentendido de mi parte.
Greg
1
@ClickOk - Gracias. Mi libro de cocina ofrece información básica: mysql.rjweb.org/doc.php/index_cookbook_mysql
Rick James