¿Necesito índices separados para cada tipo de consulta, o funcionará un índice de varias columnas?

22

Ya sé un poco la respuesta a esta pregunta, pero siempre siento que hay más cosas que necesito retomar sobre el tema.

Mi comprensión básica es que, en términos generales, un único índice que solo incluye todos los campos que podría estar consultando / ordenando en un momento dado probablemente no sea útil, pero he visto este tipo de cosas. Al igual que en, alguien pensó: "Bueno, si solo ponemos todo esto en un índice, la base de datos puede usarlo para encontrar lo que necesita", sin haber visto nunca un plan de ejecución para algunas de las consultas reales que se ejecutan.

Imagina una mesa así:

id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime

Que podría ver un único índice que incluye los name, customerIdy dateCreatedlos campos.

Pero entiendo que dicho índice no se usaría en una consulta como, por ejemplo:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Para tal consulta, me parece que una mejor idea sería un índice que incluyera los campos customerIdy dateCreated, siendo el customerIdcampo 'primero'. Esto crearía un índice que tendría los datos organizados de tal manera que esta consulta pudiera encontrar rápidamente lo que necesita, en el orden que necesita.

Otra cosa que veo, quizás con tanta frecuencia como la primera, son los índices individuales en cada campo; entonces, uno en cada uno name, customerIdy dateCreatedcampos.

A diferencia del primer ejemplo, este tipo de arreglo me parece a veces al menos parcialmente útil; el plan de ejecución de la consulta puede mostrar que al menos está usando el índice en customerIdpara seleccionar los registros, pero no está usando el índice con el dateCreatedcampo para ordenarlos.


Sé que esta es una pregunta amplia, porque la respuesta específica a cualquier consulta en particular en un conjunto de tablas en particular es ver lo que el plan de ejecución dice que va a hacer y, de lo contrario, tomar los detalles de las tablas y consultas en cuenta. Además, sé que depende de la frecuencia con la que se ejecute una consulta en lugar de la sobrecarga de mantener un índice particular para ella.

Pero supongo que lo que pregunto es como un "punto de partida" general para los índices, ¿tiene sentido la idea de tener índices específicos para consultas específicas y extraídas con frecuencia y los campos en las cláusulas WHERE u ORDER BY?

Andrew Barber
fuente

Respuestas:

27

Tiene razón en que su consulta de ejemplo no usaría ese índice.

El planificador de consultas considerará usar un índice si:

  • todos los campos contenidos en él están referenciados en la consulta
  • se hace referencia a algunos de los campos que comienzan desde el principio

No podrá utilizar índices que comiencen con un campo no utilizado por la consulta.

Entonces, para su ejemplo:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

consideraría índices como:

[customerId]
[customerId], [dateCreated]
[customerId], [dateCreated], [name]

pero no:

[name], [customerId], [dateCreated]

Si encuentra ambos [customerId]y [customerId], [dateCreated], [name]su decisión de preferir uno sobre el otro dependería de las estadísticas del índice que dependen de las estimaciones del saldo de datos en los campos. Si [customerId], [dateCreated]se definieran, debería preferir eso sobre los otros dos, a menos que dé un indicio específico de lo contrario.

No es raro ver un índice definido para cada campo en mi experiencia, aunque esto rara vez es óptimo ya que la administración adicional necesaria para actualizar los índices en la inserción / actualización, y el espacio adicional necesario para almacenarlos, se desperdicia cuando la mitad de es posible que nunca se usen, pero a menos que su DB vea cargas pesadas de escritura, el rendimiento no va a apestar mal incluso con los índices excesivos.

Los índices específicos para consultas frecuentes que de otro modo serían lentos debido al escaneo de tablas o índices generalmente es una buena idea, aunque no exagere ya que podría estar intercambiando un problema de rendimiento por otro. Si define [customerId], [dateCreated]como un índice, por ejemplo, recuerde que el planificador de consultas podrá usarlo para consultas que usarían un índice solo [customerId]si estuviera presente. Si bien usar solo [customerId]sería un poco más eficiente que usar el índice compuesto, esto puede mitigarse al terminar teniendo dos índices compitiendo por espacio en RAM en lugar de uno (aunque si todo su conjunto de trabajo normal se adapta fácilmente a la RAM, esta competencia de memoria adicional puede no ser un problema).

David Spillett
fuente
+1; gran información, especialmente el recordatorio (¡que tiendo a olvidar!) de que el planificador puede usar un índice compuesto en momentos en que solo necesita los primeros campos para una consulta.
Andrew Barber
6

Para responder a su pregunta original, sí, los índices deben diseñarse en torno a las consultas , no solo a la tabla . El orden de los campos en el índice es de vital importancia. Diseñar un solo índice para que sea óptimo para múltiples consultas es más difícil, y tendrá que hacer compensaciones.

Con respecto a su segundo punto, sí, un montón de índices en campos individuales individuales es molestamente común. Lo veo todo el tiempo en mi entorno, y generalmente es una señal de alerta para mí que el equipo de desarrollo no ha trabajado con un DBA para diseñar índices adecuados.

Mi estrategia para diseñar índices es indexar:

  • Campos utilizados en DONDE (en orden de selectividad)
  • Campos utilizados en ORDER BY
  • Incluya otros campos (si es necesario) para hacer un índice de cobertura

Entonces, para su ejemplo:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Probablemente diseñaría un índice en (CustomerID, dateCreated) INCLUDE (id, name). Este índice de cobertura significa que la consulta nunca tiene que llegar a la tabla original, mejorando enormemente el rendimiento.

Sin embargo, este ejemplo es casi demasiado simple. Un índice ingenuo en solo (CustomerID) funcionaría casi igual de bien (suponiendo que cada cliente solo tenga un solo representante, por lo que solo se requerirá una búsqueda de marcadores en la tabla). También podría ser beneficioso hacer un índice agrupado en (CustomerID, ID), dependiendo de qué otras consultas se ejecuten en la tabla.

BradC
fuente
+1 para "los índices deben diseñarse en torno a las consultas, no solo a la tabla", y al resto de la respuesta, como señalar que el ejemplo es muy simple.
Andrew Barber