Index Seek vs Index Scan

64

Al observar un plan de ejecución de una consulta de ejecución lenta, noté que algunos de los nodos son búsqueda de índice y algunos de ellos son exploración de índice.

¿Cuál es la diferencia entre una búsqueda de índice y una exploración de índice?

¿Cuál funciona mejor?

¿Cómo elige SQL uno sobre el otro?

Me doy cuenta de que son 3 preguntas, pero creo que responder la primera explicará las otras.

Greg
fuente
66
Tiene una buena referencia sobre use-the-index-luke .
Marian
77
No todos los escaneos son malos, a veces es la forma más eficiente de satisfacer la consulta. También tenga en cuenta que no todas las búsquedas son búsquedas: a menudo son exploraciones de rango, y la búsqueda solo indica cómo llegó al comienzo del rango.
Aaron Bertrand
@AaronBertrand, pero si llega al comienzo del rango y lo lee, básicamente significa que necesita los datos de todos modos. Además, busca el final del rango.
George Polevoy

Respuestas:

76

Versión corta: buscar es mucho mejor

Versión menos corta: la búsqueda es generalmente mucho mejor, pero muchas búsquedas (causadas por un mal diseño de consulta con desagradables subconsultas correlacionadas, por ejemplo, o porque está haciendo muchas consultas en una operación de cursor u otro bucle) pueden ser peores que un exploración, especialmente si su consulta puede terminar devolviendo datos de la mayoría de las filas de la tabla afectada.

Ayuda a cubrir a toda la familia para las operaciones de búsqueda de datos para comprender completamente las implicaciones de rendimiento.

Análisis de tabla: sin ningún índice relevante para su consulta, el planificador se ve obligado a utilizar un análisis de tabla, lo que significa que se examinan todas las filas. Esto puede hacer que cada página relacionada con los datos de la tabla se lea desde el disco, que a menudo es el peor de los casos. Tenga en cuenta que para algunas consultas utilizará una exploración de tabla incluso cuando esté presente un índice útil; esto generalmente se debe a que los datos en la tabla son tan pequeños que es más complicado atravesar los índices (si este es el caso, esperaría que planee cambiar a medida que crecen los datos, suponiendo que la medida de selectividad del índice sea buena).

Escaneos de índice con búsquedas de fila: sin encontrar un índice que pueda usarse directamente para una búsqueda, pero un índice que contiene las columnas correctas está presente, se puede usar un escaneo de índice. Por ejemplo, si tiene una tabla grande con 20 columnas con un índice en la columna 1, col2, col3 y emite SELECT col4 FROM exampletable WHERE col2=616, en este caso col2es mejor escanear el índice para consultar que escanear toda la tabla. Una vez que se encuentran las filas coincidentes, las páginas de datos deben leerse para recoger col4 para la salida (o unir más), que es lo que es la etapa de "búsqueda de marcadores" cuando la ve en los planes de consulta.

Escaneos de índice sin búsquedas de fila: si el ejemplo anterior fue SELECT col1, col2, col3 FROM exampletable WHERE col2=616entonces, no es necesario un esfuerzo adicional para leer las páginas de datos: una vez que col2=616se encuentran las coincidencias de filas de índice, se conocen todos los datos solicitados. Esta es la razón por la que a veces se ven columnas que nunca se buscarán, pero es probable que se soliciten resultados, agregados al final de los índices; puede guardar búsquedas de filas. Al agregar columnas a un índice por este motivo y solo por este motivo, agréguelos con la INCLUDEcláusula para indicarle al motor que no necesita optimizar el diseño del índice para las consultas basadas en estas columnas (esto puede acelerar las actualizaciones realizadas en esas columnas) . Los escaneos de índice también pueden resultar de consultas sin cláusulas de filtrado: SELECT col2 FROM exampletableescaneará este índice de ejemplo en lugar de las páginas de la tabla.

Búsqueda de índice (con o sin búsquedas de fila) : en una búsqueda no se considera todo el índice. Para la consulta, SELECT * FROM exampletable WHERE c1 BETWEEN 1234 AND 4567el motor de consultas puede encontrar la primera fila que coincidirá haciendo una búsqueda basada en un árbol en el índice y c1luego puede navegar el índice en orden hasta llegar al final del rango (esto es lo mismo con una consulta para c1=1234ya que podría haber muchas filas que concuerden con la condición incluso para una =operación). Esto significa que solo deben leerse las páginas de índice relevantes (más algunas necesarias para la búsqueda inicial) en lugar de cada página del índice (o tabla).

Índices agrupados : con un índice agrupado, los datos de la tabla se almacenan en los nodos hoja de ese índice en lugar de estar en una estructura de montón separada. Esto significa que nunca será necesario realizar búsquedas adicionales de filas después de encontrar filas usando ese índice, sin importar qué columnas se necesiten [a menos que tenga datos fuera de la página como TEXTcolumnas o VARCHAR(MAX)columnas que contienen datos largos].

Solo puede tener un índice agrupado por este motivo [1] , el índice agrupado es su tabla en lugar de tener una estructura de montón separada, por lo que si usa uno [2] elija dónde lo coloca cuidadosamente para obtener la máxima ganancia.

También tenga en cuenta que el índice agrupado porque la "clave de agrupación" para la tabla y se incluye en cada índice no agrupado en la tabla, por lo que un índice agrupado amplio generalmente no es una buena idea.

[1] En realidad, puede tener múltiples índices agrupados definiendo índices no agrupados que cubran o incluyan todas las columnas de la tabla, pero es probable que esto sea un desperdicio de espacio tiene un impacto en el rendimiento de escritura, así que si considera hacerlo, asegúrese de Realmente lo necesitas.

[2] Cuando digo "si se utiliza un índice agrupado", tenga en cuenta que en general se recomienda que se haga tener uno en cada mesa. Hay excepciones como con todas las reglas generales, las tablas que ven poco más que inserciones masivas y lecturas no ordenadas (tablas de preparación para procesos ETL tal vez) son el ejemplo de contador más común.

Punto adicional: Escaneos incompletos:

Es importante recordar que, dependiendo del resto de la consulta, una exploración de tabla / índice en realidad no puede explorar toda la tabla; si la lógica lo permite, el plan de consulta puede hacer que se cancele antes. El ejemplo más simple de esto es SELECT TOP(1) * FROM HugeTable: si mira el plan de consulta para eso, verá que solo se devolvió una fila del escaneo y si observa las estadísticas de E / S ( SET STATISTICS IO ON; SELECT TOP(1) * FROM HugeTable) verá que solo lee un número muy pequeño de páginas (quizás solo una).

Lo mismo puede suceder si el predicado de una cláusula WHEREo JOIN ... ONse puede ejecutar simultáneamente con la exploración que es la fuente de sus datos. La consulta planificador / corredor a veces puede ser muy inteligente acerca de empujar predicados de nuevo hacia las fuentes de datos para permitir la terminación anticipada de las exploraciones de esta manera (y, a veces se puede ser inteligente en la reordenación de las consultas para ayudar a que lo haga!). Si bien los datos fluyen de derecha a izquierda según las flechas en la pantalla del plan de consulta estándar, la lógica se ejecuta de izquierda a derecha y cada paso (de derecha a izquierda) no se ejecuta necesariamente hasta su finalización antes de que pueda comenzar el siguiente. En el ejemplo simple anterior, si observa cada bloque en el plan de consulta como agente, el SELECTagente le pide al TOPagente una fila que a su vez le pregunta alTABLE SCANagente para uno, luego el SELECTagente pide otro pero el TOPagente sabe que no hay necesidad, ni siquiera se molesta en preguntarle al lector de la mesa, el SELECTagente obtiene una respuesta "no más es relevante" y sabe que todo el trabajo está hecho. Muchas operaciones bloquean este tipo de optimización, por supuesto, tan a menudo en los ejemplos más complicados un recorrido de tabla / índice realmente no leen cada fila, pero tenga cuidado de no sacar la conclusión de que ninguna de exploración debe ser una operación costosa.

David Spillett
fuente
6

En general, las búsquedas son buenas, los escaneos son malos.

Las búsquedas son donde la consulta puede hacer un uso efectivo del índice y usarlo para encontrar las filas que necesita.

Los escaneos son donde la consulta busca a través de todo el índice tratando de encontrar lo que necesita.

¿Cómo elige SQL? En lo más profundo del optimizador de consultas, la decisión se toma en función de su consulta y los índices disponibles y la información estadística asociada con esos índices.

Hay algunos libros para leer que pueden ser de interés aquí. Ambos de la librería Red-Gate en http://www.red-gate.com/community/books/

  • Planes de ejecución de SQL Server por Grant Fritchey
  • Dentro del optimizador de consultas por Benjamin Nevarez
  • SQL Server Statistics por Holger Schmeling
Thomas Rushton
fuente
77
Para el mismo plan, un escaneo de una sola tabla es bueno, un millón de búsquedas es malo. Entonces su primera declaración no es del todo correcta.
Marian
De hecho, la búsqueda de índice y la exploración de índice tienen su propio uso, no se puede decir que una sea mejor que otra SIN el contexto de las tablas y consultas subyacentes. La mayoría de las veces, si una tabla tiene sus estadísticas inexactas, el plan de ejecución puede aparecer como subóptimo, por ejemplo, una búsqueda de índice se elige por error en lugar de una exploración de índice y viceversa.
jyao
5

Si desea profundizar en el tema, un libro muy útil (al menos para mí) es Planes de ejecución de SQL Server de Grant Fritchey, disponible gratuitamente en RedGate aquí .

Si tiene una consulta como

SELECT *
FROM myTable

SQL Server probablemente usará un escaneo de índice, ya que necesita recorrer todas las filas para mostrar los resultados requeridos.

De lo contrario,

SELECT *
FROM myTable
WHERE myID = 1

sin duda resultará en una búsqueda de índice. SQL Server utilizará la estructura del árbol B del índice myID y la recuperación de la línea adecuada será mucho más rápida.

KookieMonster
fuente
No sé si estoy de acuerdo con "ciertamente", incluso si un índice tiene myID como columna principal, una búsqueda puede no ser la respuesta óptima (depende de muchas cosas, como si es única, que puede ser verdadero en la tabla de clientes, pero no para customerID en la tabla de pedidos, cuántas columnas deben cubrirse pero no están en el índice, etc.
Aaron Bertrand
No creo que esta respuesta realmente cubra las preguntas planteadas.
Zero3
5

Otros han definido suficientemente bien las diferencias entre búsqueda y exploración. En este caso, su consulta y el planificador de ejecución deberían proporcionarle la información que necesita para ver qué valores se utilizan como predicados (filtros) para la consulta en cada parte. Por lo general, es una buena práctica agregar siempre índices no agrupados en claves externas, y dependiendo de los casos de uso en el código del programa, es posible que desee considerar la creación de índices de columnas múltiples adicionales o índices de columnas incluidos también. Con la terminología presentada aquí, una búsqueda en Google dará resultados decentes en ejemplos de cada uno.

Pero, como ejemplo, supongamos que su código está buscando Columna A y Columna B en filtros dados, pero también desea devolver los valores de Columna C y Columna E, es posible que desee crear un índice en la Columna A y B con INCLUIR opción que contiene las columnas C y E. De esa manera, una búsqueda de índice única devolverá todo lo que necesita, ya que no es necesario realizar una búsqueda para recuperar los otros valores (C y E) en la misma fila.

Kahn
fuente