El plan de ejecución NO está usando ÍNDICE, usa Escaneo de tabla

9

Sé que cuando se trata de usar un índice o un escaneo de tabla, SQL Server usa estadísticas para ver cuál es mejor.

Tengo una mesa con 20 millones de filas. Tengo un índice en (SnapshotKey, Measure) y esta consulta:

select Measure, SnapshotKey, MeasureBand
from t1
where Measure = 'FinanceFICOScore'
group by Measure, SnapshotKey, MeasureBand

La consulta devuelve 500k filas. Por lo tanto, la consulta selecciona solo el 2.5% de las filas de la tabla.

La pregunta es por qué SQL Server no usa el índice no agrupado que tengo, y usa un escaneo de tabla.

Las estadísticas se actualizan.

Es bueno mencionar que el rendimiento de la consulta es bueno.

Escaneo de tabla

Escaneo de tabla

Índice forzado

Índice de fuerza

Estructura de tabla / índice

CREATE TABLE [t1](
    [SnapshotKey] [int] NOT NULL,
    [SnapshotDt] [date] NOT NULL,
    [Measure] [nvarchar](30) NOT NULL,
    [MeasureBand] [nvarchar](30) NOT NULL,
    -- and many more fields
) ON [PRIMARY]

No hay PK en la mesa, ya que es un almacén de datos.

CREATE NONCLUSTERED INDEX [nci_SnapshotKeyMeasure] ON [t1]
(
    [SnapshotKey] ASC,
    [Measure] ASC
)

fuente

Respuestas:

16

La búsqueda de índice podría no ser la mejor opción si devuelve muchas filas y / o las filas son muy anchas. Las búsquedas pueden ser costosas si su índice no cubre. Ver # 2 aquí .

En su escenario, el optimizador de consultas estima que realizar 50,000 búsquedas individuales será más costoso que un solo escaneo. La elección del optimizador entre exploración y búsqueda (con búsquedas RID para las columnas que necesita la consulta, pero que no están presentes en el índice no agrupado) se basa en el costo estimado de cada alternativa.

El optimizador siempre elige la alternativa de menor costo que considere. Si observa la propiedad Costo estimado del subárbol en el nodo raíz de los dos planes de ejecución, verá que el plan de exploración tiene un costo estimado menor que el plan de búsqueda. Como resultado, el optimizador eligió el escaneo. Esa es esencialmente la respuesta a su pregunta.

Ahora, el modelo de costo utilizado por el optimizador se basa en suposiciones y "números mágicos" que es poco probable que coincidan con las características de rendimiento de su sistema. En particular, una suposición hecha en el modelo es que la consulta comienza a ejecutarse con ninguno de los datos requeridos o páginas de índice ya en la memoria. Otra es que la E / S secuencial (esperada para una exploración) es más barata que el patrón de E / S aleatorio asumido para las búsquedas RID. Hay muchas otras suposiciones y advertencias, demasiadas para entrar en detalles aquí.

Sin embargo, se ha demostrado que el modelo de costos en su conjunto produce planes generalmente "suficientemente buenos" para la mayoría de las consultas, en la mayoría de los esquemas de bases de datos, en la mayoría de las configuraciones de hardware, la mayoría de las veces, en todas partes. Eso es todo un logro, si lo piensas.

Las limitaciones del modelo y otros factores a veces significarán que el optimizador elige un plan que, de hecho, no es "suficientemente bueno" en absoluto. Usted informa que "el rendimiento es bueno", por lo que no parece ser el caso aquí.

Aaron Bertrand
fuente
9

En realidad, tiene 595,947 filas coincidentes, que es aproximadamente el 3% de sus datos. Por lo tanto, el costo de la búsqueda aumenta rápidamente. Suponga que tiene 100 filas por página en su tabla, eso es 200,000 páginas para leer en un escaneo de tabla. Eso es mucho más barato que hacer 595,947 búsquedas.

Con la GROUP BYcláusula en la pregunta, creo que estará mejor con una clave compuesta activada (Measure, SnapshotKey, MeasureBand).

Mire la sugerencia de "índice faltante". Le dice que incluya columnas para evitar las búsquedas. En términos más generales, si hace referencia a otras columnas en su consulta, deberán estar en las claves o INCLUDEcláusula del nuevo índice. De lo contrario, aún tendrá que hacer las 595,947 búsquedas para obtener esos valores.

Por ejemplo, para la consulta:

select Measure, SnapshotKey, MeasureBand, SUM(NumLoans), SUM(PrinBal)
from t1
where Measure = 'FinanceFICOScore'
group by Measure, SnapshotKey, MeasureBand

... necesitarías:

CREATE INDEX ixWhatever 
ON t1 (Measure, SnapshotKey, MeasureBand) 
INCLUDE (NumLoans,PrinBal);
Rob Farley
fuente
6
  1. El campo en su condición WHERE no es el campo principal del índice.

  2. Usted ha measuredefinido como NVARCHAR así como prefijo del literal con un N: where Measure = N'FinanceFICOScore'.

Considere crear un índice agrupado en SnapshotKey. Si es único, puede ser un PK (y agrupado). Si no es único, no puede ser un PK, pero aún puede ser un índice agrupado no único. Entonces su índice no agrupado estaría solo en la measurecolumna.

Y, considerando que el primer campo en el GROUP BYes también measure, eso también se beneficiaría de measureser el campo líder.

De hecho, para esta operación, es posible que deba definir el Índice no agrupado Measure, SnapshotKey, MeasureBanden ese orden exacto, ya que coincide con la GROUP BYcláusula. En cuanto al tamaño, solo se agrega realmente MeasureBandya que el índice NonClustered ya se basa en Measure, y MeasureKeyya está incluido en el índice, ya que ahora es la clave del Índice Clustered (no, Measureno se duplicará en el índice NonClustered).

@Rob había mencionado en un comentario ahora eliminado sobre su respuesta que resolver este problema solo requiere que el Índice no agrupado se defina con estos tres campos en este orden, y que SnapshotKeyno es necesario crear un Índice agrupado (no único) . Si bien es probable que tenga razón (esperaba que funcionaran menos campos), todavía afirmaría que tener el Índice agrupado es beneficioso no solo para esta operación, sino probablemente para la mayoría de los demás.

Solomon Rutzky
fuente
La discusión sobre esta respuesta se ha trasladado al chat .
Paul White 9