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


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.