Эти два запроса логически эквивалентны?


10

Эти два запроса логически эквивалентны?

DECLARE @DateTime DATETIME = GETDATE()

Запрос 1

SELECT *
FROM   MyTable
WHERE  Datediff(DAY, LogInsertTime, @DateTime) > 7   

Запрос 2

SELECT *
FROM   MyTable
WHERE  LogInsertTime < @DateTime - 7 

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


Какой тип LogInsertTimeесть?
Дезсо


LogInsertTime - DATETIME
Alf47

Ответы:


15

Являются ли два запроса, которые вы разместили, логически эквивалентными, не имеет значения; Вы не должны использовать ни один из них. Я постараюсь увести тебя от пары вещей:

  1. По возможности старайтесь не применять функции к столбцам. Всегда лучше и в основном лучше сохранять эти вычисления для констант, а не для столбцов - это может разрушить SARGability и сделать индексы для этих столбцов бесполезными. В этом случае я очень предпочитаю запрос 2, особенно если LogDateTimeон проиндексирован (или может когда-либо быть).
  2. Мне не нравится сокращенная дата математика, и я рекомендую против этого. Конечно, печатать быстрее, но попробуйте это с DATEтипом данных, и вы получите ужасную ошибку. Гораздо лучше объяснить это, например:

    WHERE LogInsertTime < DATEADD(DAY, -7, @DateTime);

Я согласен, моя цель состояла в том, чтобы изменить запрос 1 во что-то похожее на запрос 2, чтобы индексы могли эффективно использоваться. Спасибо за вашу помощь
Alf47

8

Я бы использовал следующий sargeable запрос:

SELECT * FROM MyTable WHERE LogInsertTime < DATEADD(DAY, -7, @DateTime)

Причина: я считаю, что результат @ DateTime-7 не задокументирован. Даже если он просто эквивалентен DATEADD (DAY, -7, @DateTime), он может сломаться в более позднем выпуске.


Отлично, это именно то, что я искал, спасибо
Alf47

2
Это, по сути, задокументированы и четко определены : - (Subtract): Subtracts two numbers (an arithmetic subtraction operator). Can also subtract a number, in days, from a date.. Тем не менее, я согласен, что использование явных функций даты делает полученный запрос более читабельным и понятным, чем «магия арифметических операторов».
Хайнци

6

Они не эквивалентны. Записи, которые были 7 дней назад, но до текущего времени суток - будут возвращены только в запросе № 2:

При сравнении дней с использованием DATEADDфункции , она не принимает часть времени во внимание . Функция вернет 1 при сравнении воскресенья и понедельника независимо от времени.

Демо-версия:

DECLARE @MyTable TABLE(pk INT, LogInsertTime DATETIME);

INSERT @MyTable
VALUES (1, DATEADD(HOUR, 1, CAST(DATEADD(DAY, -7, CAST (GETDATE() AS DATE))AS DATETIME))),
(2, DATEADD(HOUR, 23, CAST(DATEADD(DAY, -7, CAST (GETDATE() AS DATE)) AS DATETIME)));

DECLARE @DateTime DATETIME = GETDATE();

SELECT *
FROM @MyTable
WHERE DATEDIFF(DAY, LogInsertTime, @DateTime) > 7;

-- 0 records.

SELECT *
FROM @MyTable
WHERE LogInsertTime < @DateTime - 7;
-- 1 record.

Логическим эквивалентом первого запроса, который позволит использовать потенциальные индексы, является либо удаление части времени, @DateTimeлибо установка времени 0:00:00:

SELECT *
FROM @MyTable
WHERE LogInsertTime < CAST(@DateTime - 7 AS DATE);

Причина, по которой первый запрос не может использовать индекс, LogInsertTimeзаключается в том, что столбец скрыт внутри функции. Запрос № 2 сравнивает столбец с постоянным значением, которое позволяет оптимизатору выбирать индекс LogInsertTime.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.