Queste due query sono logicamente equivalenti?


10

Queste due query sono logicamente equivalenti?

DECLARE @DateTime DATETIME = GETDATE()

Query 1

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

Query 2

SELECT *
FROM   MyTable
WHERE  LogInsertTime < @DateTime - 7 

Se non sono logicamente equivalenti, puoi darmi l'equivalente logico della prima query in modo che la clausola WHERE possa effettivamente utilizzare un indice (ovvero eliminare il wrapping delle funzioni)?


Che tipo LogInsertTimeè?
dezso,


LogInsertTime è un DATETIME
Alf47

Risposte:


15

Se le due query che hai pubblicato sono logicamente equivalenti è irrilevante; non dovresti usare nessuno dei due. Proverò ad allontanarti da un paio di cose:

  1. Quando possibile, cerca di evitare di applicare funzioni alle colonne. È sempre buono, e soprattutto meglio, mantenere quei calcoli contro costanti e non colonne - questo può distruggere la SARGability e rendere inutili gli indici su quelle colonne. In questo caso, preferisco di gran lunga la query 2, specialmente se LogDateTimeè indicizzata (o potrebbe mai esserlo).
  2. Non mi piace la matematica abbreviata e sconsiglio. Certo, è più veloce da digitare, ma provalo con un DATEtipo di dati e otterrai un brutto errore. Molto meglio precisarlo, ad esempio:

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

Sono d'accordo, il mio obiettivo era quello di cambiare la query 1 in qualcosa di simile alla query 2 in modo che gli indici potessero essere effettivamente utilizzati. Grazie per l'aiuto
Alf47

8

Vorrei utilizzare la seguente query di grandi dimensioni:

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

Il motivo: credo che il risultato di @ DateTime-7 non sia documentato. Anche se sembra essere equivalente a DATEADD (DAY, -7, @DateTime), potrebbe essere interrotto in una versione successiva.


Fantastico, è esattamente quello che cercavo, grazie
Alf47,

2
E ', infatti, documentato e ben definito : - (Subtract): Subtracts two numbers (an arithmetic subtraction operator). Can also subtract a number, in days, from a date.. Tuttavia, concordo sul fatto che l'uso di funzioni di data esplicite rende la query risultante più leggibile e gestibile della "magia dell'operatore aritmetico".
Heinzi,

6

Non sono equivalenti. I record che sono 7 giorni fa, ma prima dell'ora corrente del giorno - verranno restituiti solo nella query n. 2:

Quando si confrontano i giorni utilizzando la DATEADDfunzione , non prende in considerazione la parte temporale . La funzione restituirà 1 quando si confrontano domenica e lunedì, indipendentemente dagli orari.

demo:

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.

L'equivalente logico della prima query che consentirà un potenziale utilizzo dell'indice è rimuovere la parte temporale @DateTimeo impostare l'ora su 0:00:00:

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

Il motivo per cui la prima query non può utilizzare un indice LogInsertTimeè perché la colonna è sepolta all'interno di una funzione. La query n. 2 confronta la colonna con un valore costante che consente all'ottimizzatore di scegliere un indice LogInsertTime.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.