Ці два запити логічно еквівалентні?


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
ДАТЕТИМ

Відповіді:


15

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

  1. По можливості намагайтеся уникати застосування функцій до стовпців. Завжди так само добре, і головним чином, краще зберігати ці обчислення на константах, а не стовпцях - це може знищити SARGability та зробити індекси цих стовпців марними. У цьому випадку я віддаю перевагу запиту 2, особливо якщо LogDateTimeвін індексований (або може коли-небудь бути).
  2. Мені не подобається математика скорочень дати, і я рекомендую проти цього. Звичайно, швидше набирати текст, але спробуйте це з DATEтипом даних, і ви отримаєте некрасиву помилку. Набагато краще прописати це, наприклад:

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

Я погоджуюся, моя мета полягала в тому, щоб змінити запит 1 на щось подібне до запиту 2, щоб індекси можна було ефективно використовувати. Дякую за допомогу
Alf47

8

Я використовував би такий запит, який можна отримати на зразок:

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

Причина: я вважаю, що результат @ DateTime-7 не задокументований. Навіть якщо це просто еквівалентно DATEADD (DAY, -7, @DateTime), він може зламатися в подальшому випуску.



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.