Sind diese beiden Abfragen logisch gleichwertig?

10

Sind diese beiden Abfragen logisch gleichwertig?

DECLARE @DateTime DATETIME = GETDATE()

Abfrage 1

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

Abfrage 2

SELECT *
FROM   MyTable
WHERE  LogInsertTime < @DateTime - 7 

Wenn sie nicht logisch äquivalent sind, können Sie mir das logische Äquivalent der ersten Abfrage geben, damit die WHERE-Klausel einen Index effektiv verwenden kann (dh Funktionsumbruch eliminieren)?

Alf47
quelle
Welcher Typ LogInsertTimeist?
Dekso
1
Schauen Sie sich knowdotnet.com/articles/getdatereturn.html an .
a1ex07
LogInsertTime ist eine DATETIME
Alf47

Antworten:

15

Ob die beiden von Ihnen geposteten Abfragen logisch gleichwertig sind, spielt keine Rolle. Sie sollten keinen von ihnen verwenden. Ich werde versuchen, Sie von ein paar Dingen wegzulenken:

  1. Vermeiden Sie nach Möglichkeit das Anwenden von Funktionen auf Spalten. Es ist immer genauso gut und meistens besser, diese Berechnungen gegen Konstanten und nicht gegen Spalten zu halten - dies kann die SARGability zerstören und Indizes für diese Spalten unbrauchbar machen. In diesem Fall bevorzuge ich Abfrage 2 sehr, insbesondere wenn sie LogDateTimeindiziert ist (oder jemals sein könnte).
  2. Ich mag die Kurzdatumsmathematik nicht und empfehle dagegen. Sicher, es ist schneller zu tippen, aber versuchen Sie das mit einem DATEDatentyp und Sie werden einen hässlichen Fehler erhalten. Viel besser, um es zu formulieren, zB:

    WHERE LogInsertTime < DATEADD(DAY, -7, @DateTime);
Aaron Bertrand
quelle
Ich stimme zu, mein Ziel war es, Abfrage 1 in etwas Ähnliches wie Abfrage 2 zu ändern, damit die Indizes effektiv verwendet werden können. Vielen Dank für Ihre Hilfe
Alf47
8

Ich würde die folgende sargeable Abfrage verwenden:

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

Der Grund: Ich glaube, dass das Ergebnis von @ DateTime-7 nicht dokumentiert ist. Selbst wenn es zufällig DATEADD (DAY, -7, @DateTime) entspricht, kann es in einer späteren Version nicht mehr funktionieren.

AK
quelle
Großartig, genau das habe ich gesucht, danke
Alf47
2
Es ist in der Tat dokumentiert und genau definiert : - (Subtract): Subtracts two numbers (an arithmetic subtraction operator). Can also subtract a number, in days, from a date.. Ich stimme jedoch zu, dass die Verwendung expliziter Datumsfunktionen die resultierende Abfrage lesbarer und wartbarer macht als "arithmetische Operatormagie".
Heinzi
6

Sie sind nicht gleichwertig. Datensätze, die vor 7 Tagen, aber vor der aktuellen Tageszeit erstellt wurden, werden nur in Abfrage 2 zurückgegeben:

Beim Vergleichen von Tagen mit der DATEADDFunktion wird der Zeitteil nicht berücksichtigt . Die Funktion gibt beim Vergleich von Sonntag und Montag unabhängig von der Uhrzeit 1 zurück.

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.

Das logische Äquivalent der ersten Abfrage, die eine potenzielle Indexnutzung ermöglicht, besteht darin, entweder den Zeitteil von zu entfernen @DateTimeoder die Zeit auf Folgendes festzulegen 0:00:00:

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

Der Grund, warum die erste Abfrage keinen Index für verwenden kann, LogInsertTimeliegt darin, dass die Spalte in einer Funktion vergraben ist. Abfrage Nr. 2 vergleicht die Spalte mit einem konstanten Wert, mit dem der Optimierer einen Index für auswählen kann LogInsertTime.

Der Scrum Meister
quelle