У меня есть запрос, который использует функцию предиката, что-то вроде этого:
commentType = 'EL'
AND commentDateTime >= DATEADD(month,datediff(month,0,getdate()) - 13,0)
У меня есть отфильтрованный индекс для commentType, содержащий 40 тыс. Строк, и когда я запускаю запрос, предполагаемое количество строк для поиска по индексу очень точное (около 11 КБ), но для следующего шага (оператор сортировки) он полностью игнорирует статистику и просто оценивает общее количество строк в отфильтрованном индексе.
Почему это происходит? Я знаю основы о sargability , и я проверил только ради здравомыслия, заменив dateadd на фактическую дату (2014-01-01) и вуаля ... Сортировка начала угадывать количество строк правильно ...
Почему это происходит и как я могу это исправить? Я не могу передать фиксированную дату ...
sql-server
index
statistics
MrKudz
источник
источник
DATEADD(month,datediff(month,0,getdate()) - 13,0)
не имеет смысла для меня. Что вы пытаетесь сделать с этим? Может ли это быть улучшено / упрощено?DATEADD(month, -13, DATEADD(day, 1-DATEPART(day, SYSDATETIME()))
и посмотреть, есть ли разница?(commentType, commentDate)
, он ведет себя там лучше? Просто отфильтрованные индексы могут иногда искажать оценки в разных точках планов. Оценка кажется неправильной, сообщая общее число в отфильтрованном индексе, но на самом деле план показывается неверно.Ответы:
Я считаю, что ваши оценки неверны из-за ошибки оценщика, которая заменяет два аргумента DATEDIFF. Я говорю об этом здесь:
Обходной путь - вычислить первый день 13 месяцев назад без использования DATEDIFF (2008+):
Я не уверен, что это даст оценку (я не тестировал с отфильтрованными индексами, и я не уверен, что на самом деле делает сортировка или почему у нее другая оценка без плана и / или остальной части запроса ).
Исправление, которое рекомендует Microsoft, - это использование TF 4199, но я не уверен, что это то, что вам нужно сделать здесь:
Другой вариант - убедиться, что вы используете новейшую версию SP / CU для любой версии SQL Server, которую вы используете, поскольку они утверждают, что это исправлено в следующей статье базы знаний (хотя для этого по-прежнему потребуется использование TF 4199). если вы не на 2014 или лучше):
Исправление можно получить с помощью следующих сборок:
(В следующий раз, пожалуйста, включите результаты
SELECT @@VERSION
в ваш вопрос.)Отмечу, что в статье КБ говорится, что DATEDIFF может недооценивать количество строк, что противоположно тому, что происходит в вашем сценарии. Это не значит, что исправления не относятся к вам; Я думаю, что формулировка статьи в КБ является неточной, поскольку оценки могут идти в любом направлении в зависимости от данных и диапазона, на который вы смотрите.
Мой пост в блоге выше подтвердил, что обмен больше не происходит в 2014 году и выше. Чтобы быть в безопасности, я бы, вероятно, просто удалил DATEDIFF из вашего предиката и использовал другой метод для вычисления начала вашего диапазона. Я не предлагаю превышение 4199 или использование динамического SQL, чтобы предотвратить неудачный обмен.
источник