Почему мой поиск по индексу может оценить правильное количество строк, а оператор сортировки - нет?

11

У меня есть запрос, который использует функцию предиката, что-то вроде этого:

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

У меня есть отфильтрованный индекс для commentType, содержащий 40 тыс. Строк, и когда я запускаю запрос, предполагаемое количество строк для поиска по индексу очень точное (около 11 КБ), но для следующего шага (оператор сортировки) он полностью игнорирует статистику и просто оценивает общее количество строк в отфильтрованном индексе.

Почему это происходит? Я знаю основы о sargability , и я проверил только ради здравомыслия, заменив dateadd на фактическую дату (2014-01-01) и вуаля ... Сортировка начала угадывать количество строк правильно ...

Почему это происходит и как я могу это исправить? Я не могу передать фиксированную дату ...

MrKudz
источник
DATEADD(month,datediff(month,0,getdate()) - 13,0)не имеет смысла для меня. Что вы пытаетесь сделать с этим? Может ли это быть улучшено / упрощено?
Даниэль Хутмахер
2
@Daniel Это начало месяца, 13 месяцев назад.
Аарон Бертран
1
Также, пожалуйста, отредактируйте ваш вопрос, чтобы отразить версию SQL Server (?), На которой вы работаете. Используйте теги для этого.
Даниэль Хутмахер
Не могли бы вы попробовать DATEADD(month, -13, DATEADD(day, 1-DATEPART(day, SYSDATETIME()))и посмотреть, есть ли разница?
Даниэль Хутмахер
Если у вас есть нефильтрованный индекс (commentType, commentDate), он ведет себя там лучше? Просто отфильтрованные индексы могут иногда искажать оценки в разных точках планов. Оценка кажется неправильной, сообщая общее число в отфильтрованном индексе, но на самом деле план показывается неверно.
Роб Фарли

Ответы:

9

Я считаю, что ваши оценки неверны из-за ошибки оценщика, которая заменяет два аргумента DATEDIFF. Я говорю об этом здесь:

Обходной путь - вычислить первый день 13 месяцев назад без использования DATEDIFF (2008+):

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

Я не уверен, что это даст оценку (я не тестировал с отфильтрованными индексами, и я не уверен, что на самом деле делает сортировка или почему у нее другая оценка без плана и / или остальной части запроса ).

Исправление, которое рекомендует Microsoft, - это использование TF 4199, но я не уверен, что это то, что вам нужно сделать здесь:

Другой вариант - убедиться, что вы используете новейшую версию SP / CU для любой версии SQL Server, которую вы используете, поскольку они утверждают, что это исправлено в следующей статье базы знаний (хотя для этого по-прежнему потребуется использование TF 4199). если вы не на 2014 или лучше):

Исправление можно получить с помощью следующих сборок:

  • SP3 2005 CU 15 (> = 9.00.4325 И <= 9.00.4999)
  • 2005 SP4 CU 2 (> = 9.00.5259)
  • 2008 SP1 CU 13 (> = 10.00.2816.00 И <= 10.00.3999)
  • 2008 SP2 CU 3 (> = 10.00.4279.00 И <= 10.00.5499)
  • К расширению 2008 SP3 & SP4 (> = 10.00.5500)
  • 2008 R2 CU 7 (10.50.1777.0)
  • 2008 R2 SP1 CU 3 (> = 10.50.2769.0 И <= 10.50.3999)
  • К расширению 2008 R2 SP2 и SP3 (> = 10.50.4000)
  • По расширению 2012, 2014, 2016 (> = 11,0)

(В следующий раз, пожалуйста, включите результаты SELECT @@VERSIONв ваш вопрос.)

Отмечу, что в статье КБ говорится, что DATEDIFF может недооценивать количество строк, что противоположно тому, что происходит в вашем сценарии. Это не значит, что исправления не относятся к вам; Я думаю, что формулировка статьи в КБ является неточной, поскольку оценки могут идти в любом направлении в зависимости от данных и диапазона, на который вы смотрите.

Мой пост в блоге выше подтвердил, что обмен больше не происходит в 2014 году и выше. Чтобы быть в безопасности, я бы, вероятно, просто удалил DATEDIFF из вашего предиката и использовал другой метод для вычисления начала вашего диапазона. Я не предлагаю превышение 4199 или использование динамического SQL, чтобы предотвратить неудачный обмен.

Аарон Бертран
источник
Спасибо за помощь ! Я попробовал ваше предложение, и план изменился. Вот как это было раньше: s16.postimg.org/t5j6o1yed/fix_wrong.png Вот как это происходит после того, как я изменил свой номер на ваш: postimg.org/image/5f725rj83 Я собираюсь прочитать все URL, которые вы мне дали , Приветствия.
MrKudz