Pourquoi mon index peut-il estimer le bon nombre de lignes et l'opérateur de tri ne peut pas?

11

J'ai une requête qui utilise une fonction sur le prédicat, quelque chose comme ceci:

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

J'ai un index filtré sur commentType qui a 40K lignes et lorsque j'exécute la requête, le nombre estimé de lignes pour la recherche d'index est très précis (environ 11K), mais pour l'étape suivante (opérateur de tri), il ignore complètement les statistiques et estime simplement le nombre total de lignes dans l'index filtré.

Pourquoi cela arrive-t-il? Je connais les bases de la sargabilité , et j'ai testé juste pour le bien de la raison en remplaçant le dateadd par une date réelle (2014-01-01) et le tour est joué ... Le tri a commencé à deviner le nombre de lignes correctement ...

Pourquoi cela se produit-il et comment puis-je le corriger? Je ne peux pas passer une date fixe ...

MrKudz
la source
DATEADD(month,datediff(month,0,getdate()) - 13,0)n'a pas de sens pour moi. Qu'essayez-vous de faire avec ça? Peut-il être amélioré / simplifié?
Daniel Hutmacher
2
@Daniel C'est le début du mois, il y a 13 mois.
Aaron Bertrand
1
Veuillez également modifier votre question pour refléter la version de SQL Server (?) Sur laquelle vous vous trouvez. Utilisez des balises pour cela.
Daniel Hutmacher
Pourriez-vous essayer de DATEADD(month, -13, DATEADD(day, 1-DATEPART(day, SYSDATETIME()))voir s'il y a une différence?
Daniel Hutmacher
Si vous avez un index non filtré (commentType, commentDate), est-ce qu'il se comporte mieux là-bas? C'est juste que les indices filtrés peuvent parfois déformer les estimations à différents points des plans. L'estimation semble être sortie en signalant le nombre total dans l'index filtré, mais c'est en fait que le plan est affiché incorrect.
Rob Farley

Réponses:

9

Je crois que vos estimations sont fausses à cause d'un bug d'estimateur qui permute deux des arguments DATEDIFF. J'en parle ici:

Une solution de contournement consiste à calculer le premier jour d'il y a 13 mois sans utiliser DATEDIFF (2008+):

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

Je ne suis pas positif qui répondra à l'estimation (je ne l' ai pas testé avec des index filtrés, et je ne suis pas sûr de ce que le genre est en train de faire ou pourquoi il a une estimation différente sans le plan et / ou le reste de la requête ).

Le correctif recommandé par Microsoft consiste à utiliser TF 4199, mais je ne suis pas sûr que ce soit ce que vous devrez faire ici:

Une autre option serait de vous assurer que vous êtes sur le dernier SP / CU absolu pour la version de SQL Server que vous utilisez, car ils prétendent que cela est résolu dans l'article de la base de connaissances suivant (bien que cela nécessitera toujours l'utilisation de TF 4199 sauf si vous êtes en 2014 ou mieux):

Le correctif peut être obtenu avec les versions suivantes:

(La prochaine fois, veuillez inclure les résultats de SELECT @@VERSIONdans votre question.)

Je noterai que l'article de la base de connaissances dit que DATEDIFF peut sous - estimer le nombre de lignes, ce qui est l'opposé de ce qui se passe dans votre scénario. Cela ne signifie pas que les correctifs ne s'appliquent pas à vous; Je pense que le libellé de l'article de la base de connaissances est inexact, car les estimations peuvent aller dans les deux sens en fonction des données et de la plage que vous regardez.

Mon article de blog ci-dessus a confirmé que l'échange ne se produit plus en 2014 et après. Pour être sûr, je supprimerais probablement DATEDIFF de votre prédicat et utiliserais une méthode différente pour calculer le début de votre plage. Je ne suggère pas la surpuissance de 4199 ou l'utilisation de SQL dynamique pour empêcher le mauvais échange.

Aaron Bertrand
la source
Merci pour l'aide ! J'ai essayé votre suggestion et le plan a changé. Voici comment c'était avant: s16.postimg.org/t5j6o1yed/fix_wrong.png Voici comment c'est après que j'ai changé mon datiff par le vôtre: postimg.org/image/5f725rj83 Je vais lire toutes les URL que vous m'avez données . À votre santé.
MrKudz