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';
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 TransactionID
columna 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 TransactionDate
objeto 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 TransactionID
y TransactionDate
tienen 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:
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 TransactionID
predicado solo estimó 68,336.4 filas y el TransactionDate
predicado 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 AND
predicados correlacionados . Cada predicado se considera para una posible correlación, y se realizan otros ajustes cuando hay muchas AND
clá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 TransactionDate
columna.
DBCC SHOW_STATISTICS
(
'Production.TransactionHistory',
'stats Production.TransactionHistory TransactionDate TransactionID'
);
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:
Statistics objects on multiple columns also store statistical information about the correlation of values among the columns