Por que meu índice procura estimar o número certo de linhas e o operador de classificação não pode?

11

Eu tenho uma consulta que usa uma função no predicado, algo como isto:

commentType = 'EL'
AND commentDateTime >= DATEADD(month,datediff(month,0,getdate()) - 13,0)

Eu tenho um índice filtrado no commentType que tem 40K linhas e, quando executo a consulta, o número estimado de linhas para a Busca por Índice é muito preciso (em torno de 11K), mas para a próxima etapa (operador de classificação) ele ignora completamente as estatísticas e apenas estima o número total de linhas no índice filtrado.

Por que isso está acontecendo? Eu sei o básico sobre sargabilidade e testei apenas por uma questão de sanidade, substituindo os dados datados por uma data real (01-01-2014) e pronto ... O tipo começou a adivinhar o número de linhas corretamente ...

Por que isso está acontecendo e como posso corrigi-lo? Não posso passar uma data fixa ...

MrKudz
fonte
DATEADD(month,datediff(month,0,getdate()) - 13,0)não faz sentido para mim. O que você está tentando fazer com isso? Pode ser melhorado / simplificado?
Daniel Hutmacher 30/01
2
@ Daniel Esse é o começo do mês, há 13 meses.
Aaron Bertrand
1
Além disso, edite sua pergunta para refletir a versão do SQL Server (?) Em que você está. Use tags para isso.
Daniel Hutmacher
Você poderia tentar DATEADD(month, -13, DATEADD(day, 1-DATEPART(day, SYSDATETIME()))ver se há alguma diferença?
Daniel Hutmacher 30/01
Se você tem um índice não filtrado (commentType, commentDate), ele se comporta melhor lá? Às vezes, os índices filtrados podem às vezes relatar estimativas em pontos diferentes dos planos. A estimativa parece muito clara ao informar o número total no índice filtrado, mas na verdade o plano está sendo mostrado incorretamente.
precisa saber é o seguinte

Respostas:

9

Acredito que suas estimativas estão erradas por causa de um bug no estimador que troca dois dos argumentos DATEDIFF. Eu falo sobre isso aqui:

Uma solução alternativa é calcular o primeiro dia de 13 meses atrás sem usar DATEDIFF (2008 ou posterior):

DATEADD(MONTH, -13, DATEADD(DAY, 1-DATEPART(DAY,GETDATE()), CONVERT(DATE, GETDATE()));

Não tenho certeza de que abordará a estimativa (não testei com índices filtrados e não sei o que a classificação está realmente fazendo ou por que ela tem uma estimativa diferente sem o plano e / ou o restante da consulta )

A correção que a Microsoft recomenda é usar o TF 4199, mas não tenho certeza de que você precisará fazer aqui:

Outra opção seria garantir que você esteja no SP / CU mais recente absoluto para qualquer versão do SQL Server que estiver usando, pois eles alegam que o problema foi corrigido no seguinte artigo da KB (embora isso ainda exija o uso do TF 4199 a menos que você esteja em 2014 ou melhor):

A correção pode ser obtida com as seguintes compilações:

(Da próxima vez, inclua os resultados de SELECT @@VERSIONem sua pergunta.)

Observarei que o artigo da KB diz que DATEDIFF pode subestimar o número de linhas, que é o oposto do que está acontecendo no seu cenário. Isso não significa que as correções não se aplicam a você; Acho que a redação do artigo da KB é imprecisa, pois as estimativas podem variar de acordo com os dados e o intervalo que você está olhando.

Meu post acima confirmou que a troca não ocorre mais em 2014 e acima. Para estar seguro, provavelmente retiraria DATEDIFF do seu predicado e usaria um método diferente para calcular o início do seu intervalo. Não sugiro o exagero de 4199 ou o uso de SQL dinâmico para impedir a troca incorreta.

Aaron Bertrand
fonte
Obrigado pela ajuda ! Tentei sua sugestão e o plano mudou. É assim que era antes: s16.postimg.org/t5j6o1yed/fix_wrong.png É assim que eu mudei meu datediff pelo seu: postimg.org/image/5f725rj83 Vou ler todos os URLs que você me deu . Felicidades.
MrKudz