Вопрос по sql-server, sql – Является ли это условие сравнения дат SARG-совместимым в SQL?

8

Это состояние саргнину?

AND  DATEDIFF(month,p.PlayerStatusLastTransitionDate,@now) BETWEEN 1 AND 7)

Мое эмпирическое правило заключается в том, что функция слева делает условие не сарказуемым, но в некоторых местах я читал, что предложение BETWEEN саргенируемо. So does any one know for sure?

Для справки:

ПРИМЕЧАНИЕ. Если гуру заканчивается здесь, обновите страницу Sargable Wikipedia. Я немного обновил его, но я уверен, что его можно еще улучшить :)

Просто думая, что функция слева (DATEDIFF) может повлиять на проходимость (вау! Какое слово!) ... Oscar Foley
Также, пожалуйста, смотритеsqlperformance.com/2013/09/t-sql-queries/datediff-bug Aaron Bertrand
МЕЖДУ просто сокращение для & gt; = AND & lt; =. Почему в этом случае это может повлиять на гибкость? Aaron Bertrand

Ваш Ответ

2   ответа
20

если мы посмотрим на эти два эквивалентных запроса:

SELECT OrderDate FROM Sales.SalesOrderHeader
WHERE DATEDIFF(month,OrderDate,GETDATE()) BETWEEN 1 AND 7;

SELECT OrderDate FROM Sales.SalesOrderHeader
WHERE OrderDate >= DATEADD(MONTH, -7, GETDATE())
  AND OrderDate <= DATEADD(MONTH, -1, GETDATE());

В обоих случаях мы видим сканирование кластерного индекса:

enter image description here

Но обратите внимание на рекомендуемый / отсутствующий индекс только в последнем запросе, поскольку он единственный, который может извлечь из этого пользу:

enter image description here

Если мы добавим индекс в столбец OrderDate, то снова запустим запросы:

CREATE INDEX dt ON Sales.SalesOrderHeader(OrderDate);
GO

SELECT OrderDate FROM Sales.SalesOrderHeader
WHERE DATEDIFF(month,OrderDate,GETDATE()) BETWEEN 1 AND 7;

SELECT OrderDate FROM Sales.SalesOrderHeader
WHERE OrderDate >= DATEADD(MONTH, -7, GETDATE())
  AND OrderDate <= DATEADD(MONTH, -1, GETDATE());

Мы видим большую разницу - последний использует поиск:

enter image description here

enter image description here

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

Очень мало случаев, когда функция или другое выражение, примененное к столбцу, будет пригодным для использования. Один известный мне случайCONVERT(DATE, datetime_column) - но эта конкретная оптимизация недокументирована, и я все равно рекомендую держаться от нее подальше. Не только потому, что вы неявно предполагаете, что использование функций / выражений для столбцов нормально (это не в любом другом сценарии), но и потому, чтоэто может привести к потерянным прочтениям и катастрофическим оценкам.

8

если бы это было саркастично. Один из вариантов может быть переписать его как:

WHERE p.PlayerStatusLastTransitionDate >= DATEADD(month,1,CAST(@now AS DATE))
AND   p.PlayerStatusLastTransitionDate <= DATEADD(month,7,CAST(@now AS DATE))

Который, я полагаю, будет саркастичным (хотя это и не так красиво).

Этот ответ можно перефразировать с помощьюBETWEEN, Важно то, что функция даты применяется к выражениям, которые являются постоянными для выполнения запроса, а не применяется к каждой строке, как в запросе OP.
@ user92546, хорошая точка
Я не рекомендую использовать BETWEEN для запросов даты и времени, в вашем собственном коде или для кода, который вы предоставляете другим. Вот почему:sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/…
+1: запрос OPS не SARGable.table.field BETWEEN f(x) AND f(y) (or using >= and <= as Abe has done) SARGable. В значительной степени, если вы поместите поле поиска в функцию, оно не будет SARGable. Вместо этого обработайте параметры для поиска, как ответ Абэ :)

Похожие вопросы