O plano Real completo está aqui.
Antes de executar o plano (porque estou depurando um plano que funciona mal), tenho este bloco de atribuições de variáveis:
DECLARE @Days INT = 180
DECLARE @DateRangeFrom DateTime = DATEADD(d, -@Days, getDate())
DECLARE @DateRangeTo DateTime = getDate()
DECLARE @FacilityID INT = 1010
DECLARE @Answer0 INT = 1879
DECLARE @Answer1 INT = 1949
DECLARE @Answer1SetID INT = 1607
DECLARE @Answer2 INT = 1907
DECLARE @Answer2SetID INT = 1593
Meu primeiro problema é com a pesquisa que estou realizando na tabela IRItemAnswer_Info (Node ID 19). Está se espalhando para o Tempdb, que já inicia a consulta com o pé errado. Ele está referenciando o IRItemAnswerInfo_DGItemID_AnswerSourceID
índice, que é o índice correto, pois estou combinando em DGItemID
e AnswerSourceID
, e retornando IncidentID
. O índice é criado como
CREATE NONCLUSTERED INDEX IRItemAnswerInfo_DGItemID_AnswerSourceID
ON dbo.IRItemAnswer_Info (DGItemID, AnswerSourceID)
INCLUDE([IncidentID], [AnswerBoolean])
No entanto, as linhas estimadas para a consulta são 53.459 e as linhas reais são 969.812.
Acabei de forçar novas estatísticas via UPDATE STATISTICS IRItemAnswer_Info IRItemAnswerInfo_DGItemID_AnswerSourceID WITH FULLSCAN
e não fez diferença.
DBCC SHOW_STATISTICS ('IRItemAnswer_Info', 'DGItemID')
para DGItemID=1949
tem EQ_ROWS
como 1,063,536
e
DBCC SHOW_STATISTICS ('IRItemAnswer_Info', 'AnswerSourceID')
para AnswerSourceID=1607
tem EQ_ROWS
como970,079
O banco de dados está executando o nível de compatibilidade 140 (SQL Server 2017). Executamos 2019, mas há problemas que precisamos corrigir nos procedimentos armazenados antes de podermos fazer isso.
Qual deve ser a próxima coisa que eu olho?
Escolhi a saída com pior desempenho, que são os valores mais comuns. IRItemAnswer_Info
é uma tabela contendo respostas definidas pelo usuário para associar a um evento, onde DGItemID=1949
é uma das perguntas mais comuns (quase todo evento tem uma) e onde AnswerSourceID=1607
é a resposta mais comum. Dado que existe uma forte correlação entre eles, como devo reordenar a consulta?
Como é um ponto de um pouco de confusão, existem dois INNER JOIN
s para a mesma tabela, IRItemAnswer_Info
. Uma é a resposta que estou procurando (conforme identificado pela pergunta e seus links de iria.DGItemID=1879
saída para ), e a segunda é um fator limitante. Eu só quero registros onde a pergunta tenha como resposta .iria.AnswerSourceID
irai.AltLabel
iiai1.DGItemID=1949
iiai1.AnswerSourceID=1607
Eu removi explicitamente o plano do cache (usando DBCC FREEPROCCACHE
) e o executei novamente, sem alteração no resultado - o Hash Match ainda está derramando.
Conforme discutido nas perguntas e respostas relacionadas, como o SQL Server sabe que os predicados estão correlacionados? O SQL Server assume que os predicados são completamente independentes por padrão.
Ele só tem informações estatísticas detalhadas (histogramas) na única coluna inicial, mesmo quando são usados índices ou estatísticas de várias colunas. A questão então é como combinar dois histogramas estatísticos de dois predicados separados.
Por exemplo, digamos que você tenha uma consulta com
WHERE c1 = x AND c2 = y
. A seletividade dec1 = x
é calculada como 0,2 a partir da informação do histograma. A seletividade dec2 = y
é calculada como 0,1 a partir de um histograma separado.Qual é a seletividade dos dois predicados juntos? 0,2? 0,1? 0,2 x 0,1? Em algum lugar no meio?
Sem informações adicionais específicas, o SQL Server precisa fazer um palpite. O padrão original era assumir total independência. A estrutura de estimativa de cardinalidade mais recente usa recuo exponencial (a opção 'em algum lugar no meio').
Seu caso é um pouco diferente, pois você tem dois testes de igualdade em colunas em um índice de várias colunas, que vem com estatísticas de várias colunas. Estes não são tão grandiosos como podem parecer. Ainda obtemos apenas um histograma na coluna principal, mas o objeto de estatísticas contém informações de densidade média para várias colunas.
Por exemplo, um índice em (a,b,c) forneceria informações de densidade para (a), (a,b) e (a,b,c). Essas informações de frequência capturam algo sobre correlação, mas é um único número em cada nível. Isso significa que uma estimativa baseada em frequência sempre produzirá a mesma estimativa com o mesmo número de colunas.
O SQL Server produz uma estimativa de seletividade a partir das informações de frequência de várias colunas, mas também calcula a seletividade dos histogramas de colunas individuais (quando disponíveis). A estimativa do histograma assume independência e não usa recuo exponencial.
O servidor escolhe a estimativa baseada em histograma se for uma seletividade mais alta do que a estimativa baseada em frequência. Este parece ser o caso no seu exemplo.
A partir das informações da pergunta, as seletividades individuais são:
Assumindo independência, pois
AND
multiplicamos essas seletividades e depois multiplicamos pela cardinalidade da tabela completa para produzir a estimativa de linha:Há uma série de variações de modelos internos que abordam a tarefa de maneiras diferentes. Apenas alguns são documentados publicamente e expostos por meio de dicas ou sinalizadores de rastreamento.
Normalmente, parece que a seguinte dica pode ser útil:
Documentação
Infelizmente, essa dica não se aplica quando a estimativa de cardinalidade começou com um cálculo baseado em frequência, usando estatísticas de várias colunas.
Você pode obter um resultado melhor no seu caso usando o modelo CE original:
Tente este índice em vez disso
A outra coisa que eu consideraria se isso não ajudar é solucionar problemas do índice como uma única seleção (sem junções) e colocar os resultados diretamente em uma tabela temporária e, em seguida, juntar-se a ela mais tarde.
Por exemplo, tente algo como a consulta abaixo e veja se consegue obter estimativas corretas. Se puder, isso deve confirmar que você encontrou o índice correto. Em seguida, amarre todo o resto de volta.
Você pode tentar, com a seguinte reescrita:
Você também pode tentar com:
Pelo menos, verifique se você tem esses índices:
Se não criar e testar...