¿Cómo sabe SQL Server que los predicados están correlacionados?

15

Mientras diagnosticaba consultas de SQL Server 2008 R2 con una estimación de cardinalidad deficiente (a pesar de la indexación simple, estadísticas actualizadas, etc.) y, por lo tanto, planes de consulta deficientes, encontré un artículo de KB quizás relacionado: REVISIÓN: bajo rendimiento cuando ejecuta una consulta que contiene predicados AND correlacionados en SQL Server 2008 o en SQL Server 2008 R2 o en SQL Server 2012

Puedo adivinar qué quiere decir el artículo de KB con "correlacionado", por ejemplo, el predicado # 2 y el predicado # 1 apuntan en gran medida a las mismas filas.

Pero no sé cómo SQL Server sabe acerca de estas correlaciones. ¿Necesita una tabla un índice de varias columnas que contenga columnas de ambos predicados? ¿Utiliza SQL estadísticas para verificar si los valores de una columna están correlacionados con otra? ¿O se usa algún otro método?

Estoy preguntando esto por dos razones:

  1. para determinar cuáles de mis tablas y consultas podrían mejorarse utilizando esta revisión
  2. saber qué debo hacer en indexación, estadísticas, etc. para afectar el n. ° 1
Justin Grant
fuente

Respuestas:

20

Considere el plan simple de consulta y ejecución de AdventureWorks que se muestra a continuación. La consulta contiene predicados conectados con AND. La estimación de cardinalidad del optimizador es de 41.211 filas:

-- Estimate 41,211 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionID BETWEEN 100000 AND 168336
    AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';

Plan de ejecución predeterminado

Usar estadísticas predeterminadas

Dado que solo hay estadísticas de una sola columna, el optimizador produce esta estimación al estimar la cardinalidad para cada predicado por separado y multiplicando las selectividades resultantes. Esta heurística supone que los predicados son completamente independientes.

Dividir la consulta en dos partes hace que el cálculo sea más fácil de ver:

-- Estimate 68,336.4 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionID BETWEEN 100000 AND 168336;

La tabla Historial de transacciones contiene 113,443 filas en total, por lo que la estimación 68,336.4 representa una selectividad de 68336.4 / 113443 = 0.60238533 para este predicado. Esta estimación se obtiene utilizando la información del histograma para la TransactionIDcolumna y los valores constantes especificados en la consulta.

-- Estimate 68,413 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';

Este predicado tiene una selectividad estimada de 68413.0 / 113443 = 0.60306056 . Nuevamente, se calcula a partir de los valores constantes del predicado y el histograma del TransactionDateobjeto estadístico.

Suponiendo que los predicados son completamente independientes, podemos estimar la selectividad de los dos predicados juntos multiplicándolos juntos. La estimación de cardinalidad final se obtiene multiplicando la selectividad resultante por las 113,443 filas en la tabla base:

0,60238533 * 0,60306056 * 113443 = 41210,987

Después del redondeo, esta es la estimación de 41,211 vista en la consulta original (el optimizador también usa matemática de punto flotante internamente).

No es una gran estimación

Las columnas TransactionIDy TransactionDatetienen una estrecha correlación en el conjunto de datos de AdventureWorks (como las claves de aumento monotónico y las columnas de fecha a menudo lo hacen). Esta correlación significa que se viola el supuesto de independencia. Como consecuencia, el plan de consulta posterior a la ejecución muestra 68.095 filas en lugar de las estimadas 41.211:

Plan posterior a la ejecución

Traza bandera 4137

Habilitar este indicador de traza cambia las heurísticas utilizadas para combinar predicados. En lugar de asumir una independencia completa, el optimizador considera que las selectividades de los dos predicados son lo suficientemente cercanas como para que puedan estar correlacionadas:

-- Estimate 68,336.4
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionID BETWEEN 100000 AND 168336
    AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13'
OPTION (QUERYTRACEON 4137);

Recuerde que el TransactionIDpredicado solo estimó 68,336.4 filas y el TransactionDatepredicado solo estimó 68,413 filas. El optimizador ha elegido la más baja de estas dos estimaciones en lugar de multiplicar las selectividades.

Esto es solo una heurística diferente, por supuesto, pero que puede ayudar a mejorar las estimaciones de consultas con ANDpredicados correlacionados . Cada predicado se considera para una posible correlación, y se realizan otros ajustes cuando hay muchas ANDcláusulas involucradas, pero ese ejemplo sirve para mostrar los conceptos básicos.

Estadísticas de varias columnas

Estos pueden ayudar en las consultas con correlaciones, pero la información del histograma todavía se basa únicamente en la columna principal de las estadísticas. Por lo tanto, las siguientes estadísticas de múltiples columnas candidatas difieren de manera importante:

CREATE STATISTICS
    [stats Production.TransactionHistory TransactionID TransactionDate]
ON Production.TransactionHistory
    (TransactionID, TransactionDate);

CREATE STATISTICS
    [stats Production.TransactionHistory TransactionDate TransactionID]
ON Production.TransactionHistory
    (TransactionDate, TransactionID);

Tomando solo uno de esos, podemos ver que la única información adicional son los niveles adicionales de la densidad 'total'. El histograma solo contiene información detallada sobre la TransactionDatecolumna.

DBCC SHOW_STATISTICS
    (
        'Production.TransactionHistory', 
        'stats Production.TransactionHistory TransactionDate TransactionID'
    );

Estática de múltiples columnas

Con estas estadísticas de varias columnas en su lugar ...

SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE 
    TH.TransactionID BETWEEN 100000 AND 168336
    AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';

... el plan de ejecución muestra una estimación que es exactamente la misma que cuando solo estaban disponibles estadísticas de una sola columna:

Plan estadístico de columnas múltiples

Paul White reinstala a Monica
fuente