¿Son estas dos consultas lógicamente equivalentes?

10

¿Son estas dos consultas lógicamente equivalentes?

DECLARE @DateTime DATETIME = GETDATE()

Consulta 1

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

Consulta 2

SELECT *
FROM   MyTable
WHERE  LogInsertTime < @DateTime - 7 

Si no son lógicamente equivalentes, ¿puede darme el equivalente lógico de la primera consulta para que la cláusula WHERE pueda usar efectivamente un índice (es decir, eliminar el ajuste de función)?

Alf47
fuente
Que tipo LogInsertTimees
dezso
1
Eche un vistazo a knowdotnet.com/articles/getdatereturn.html .
a1ex07
LogInsertTime es un DATETIME
Alf47

Respuestas:

15

Si las dos consultas que publicó son lógicamente equivalentes es irrelevante; no deberías usar ninguno de ellos. Intentaré alejarte de un par de cosas:

  1. Siempre que sea posible, trate de evitar aplicar funciones a las columnas. Siempre es tan bueno, y sobre todo mejor, mantener esos cálculos con constantes y no con columnas; esto puede destruir la capacidad de SARGabilidad e inutilizar los índices en esas columnas. En este caso, prefiero la consulta 2, especialmente si LogDateTimeestá indexada (o podría estarlo).
  2. No me gustan las matemáticas de la fecha abreviada y recomiendo no hacerlo. Claro, es más rápido escribir, pero intente eso con un DATEtipo de datos y obtendrá un error feo. Mucho mejor para explicarlo, por ejemplo:

    WHERE LogInsertTime < DATEADD(DAY, -7, @DateTime);
Aaron Bertrand
fuente
Estoy de acuerdo, mi objetivo era cambiar la consulta 1 en algo similar a la consulta 2 para que los índices pudieran usarse de manera efectiva. Gracias por su ayuda
Alf47
8

Usaría la siguiente consulta sargeable:

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

El motivo: creo que el resultado de @ DateTime-7 no está documentado. Incluso si resulta ser equivalente a DATEADD (DAY, -7, @DateTime), puede romperse en una versión posterior.

Alaska
fuente
Genial, eso es exactamente lo que estaba buscando, gracias
Alf47
2
Es, de hecho, documentado y bien definida : - (Subtract): Subtracts two numbers (an arithmetic subtraction operator). Can also subtract a number, in days, from a date.. Aún así, estoy de acuerdo en que el uso de funciones de fecha explícitas hace que la consulta resultante sea más legible y mantenible que la "magia del operador aritmético".
Heinzi
6

No son equivalentes. Los registros de hace 7 días, pero antes de la hora actual del día , solo se devolverán en la consulta n.º 2:

Al comparar días usando la DATEADDfunción , no toma en cuenta la parte del tiempo . La función devolverá 1 al comparar domingo y lunes, independientemente de los horarios.

Manifestación:

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.

El equivalente lógico de la primera consulta que permitirá el uso potencial del índice es eliminar la parte del tiempo @DateTimeo establecer el tiempo para 0:00:00:

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

La razón por la cual la primera consulta no puede usar un índice LogInsertTimees porque la columna está enterrada dentro de una función. La consulta n. ° 2 compara la columna con un valor constante que permite al optimizador elegir un índice LogInsertTime.

El Scrum Meister
fuente