Considere o plano simples de consulta e execução AdventureWorks mostrado abaixo. A consulta contém predicados conectados AND
. A estimativa de cardinalidade do otimizador é 41.211 linhas:
-- 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';
Usando estatísticas padrão
Dadas apenas estatísticas de coluna única, o otimizador produz essa estimativa estimando a cardinalidade de cada predicado separadamente e multiplicando as seletividades resultantes juntas. Essa heurística assume que os predicados são completamente independentes.
Dividir a consulta em duas partes facilita a visualização do cálculo:
-- Estimate 68,336.4 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336;
A tabela Histórico de transações contém 113.443 linhas no total, portanto, a estimativa 68.336,4 representa uma seletividade de 68336,4 / 113443 = 0,60238533 para esse predicado. Essa estimativa é obtida usando as informações do histograma da TransactionID
coluna e os valores constantes especificados na consulta.
-- Estimate 68,413 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
Esse predicado tem uma seletividade estimada de 68413.0 / 113443 = 0.60306056 . Novamente, é calculado a partir dos valores constantes do predicado e do histograma do TransactionDate
objeto estatístico.
Supondo que os predicados sejam completamente independentes, podemos estimar a seletividade dos dois predicados juntos, multiplicando-os. A estimativa final da cardinalidade é obtida multiplicando a seletividade resultante pelas 113.443 linhas na tabela base:
0,60238533 * 0,60306056 * 113443 = 41210,987
Após o arredondamento, esta é a estimativa 41.211 vista na consulta original (o otimizador também usa matemática de ponto flutuante internamente).
Não é uma ótima estimativa
As colunas TransactionID
e TransactionDate
têm uma estreita correlação no conjunto de dados do AdventureWorks (como geralmente aumentam monotonicamente chaves e colunas de data). Essa correlação significa que a suposição de independência é violada. Como conseqüência, o plano de consulta pós-execução mostra 68.095 linhas em vez dos 41.211 estimados:
Bandeira de rastreamento 4137
A ativação desse sinalizador de rastreamento altera as heurísticas usadas para combinar predicados. Em vez de assumir total independência, o otimizador considera que as seletividades dos dois predicados são próximas o suficiente para que possam ser 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);
Lembre-se de que o TransactionID
predicado sozinho estimou 68.336,4 linhas e o TransactionDate
predicado sozinho estimou 68.413 linhas. O otimizador escolheu a menor dessas duas estimativas em vez de multiplicar as seletividades.
Essa é apenas uma heurística diferente, é claro, mas que pode ajudar a melhorar as estimativas de consultas com AND
predicados correlacionados . Cada predicado é considerado para uma possível correlação, e há outros ajustes feitos quando muitas AND
cláusulas estão envolvidas, mas esse exemplo serve para mostrar o básico.
Estatísticas de várias colunas
Isso pode ajudar nas consultas com correlações, mas as informações do histograma ainda são baseadas apenas na coluna principal das estatísticas. As seguintes estatísticas de várias colunas candidatas diferem, portanto, de uma maneira 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 apenas um deles, podemos ver que a única informação extra são os níveis extras da densidade 'all'. O histograma ainda contém apenas informações detalhadas sobre a TransactionDate
coluna.
DBCC SHOW_STATISTICS
(
'Production.TransactionHistory',
'stats Production.TransactionHistory TransactionDate TransactionID'
);
Com essas estatísticas de várias colunas no 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';
... o plano de execução mostra uma estimativa exatamente igual a quando apenas as estatísticas de coluna única estavam disponíveis:
Statistics objects on multiple columns also store statistical information about the correlation of values among the columns