Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Ist es bei der Verwendung von GETDATE() an vielen Stellen besser, eine Variable zu verwenden?

[HINWEIS:Wenn Sie diese Antwort ablehnen, hinterlassen Sie bitte einen Kommentar, in dem Sie erklären, warum. Es wurde bereits viele Male abgelehnt, und schließlich erklärte Ypercube (danke) mindestens einen Grund dafür. Ich kann die Antwort nicht entfernen, weil sie akzeptiert wird, also können Sie genauso gut helfen, sie zu verbessern.]

Laut diesem Austausch auf Microsoft, GETDATE() in SQL Server 2005 von konstant innerhalb einer Abfrage auf nicht deterministisch umgestellt. Im Nachhinein glaube ich nicht, dass das richtig ist. Ich denke, es war vor SQL Server 2005 völlig nicht deterministisch und wurde dann seit SQL Server 2005 in etwas namens "nicht deterministische Laufzeitkonstante" gehackt. Der spätere Ausdruck scheint wirklich "Konstante innerhalb einer Abfrage" zu bedeuten.

(Und GETDATE() wird als eindeutig und stolz nicht deterministisch definiert, ohne Qualifizierer.)

Leider bedeutet nicht deterministisch in SQL Server nicht, dass eine Funktion für jede Zeile ausgewertet wird. SQL Server macht dies wirklich unnötig kompliziert und mehrdeutig mit sehr wenig Dokumentation zu diesem Thema.

In der Praxis wird der Funktionsaufruf ausgewertet, wenn die Abfrage ausgeführt wird, und nicht einmal, wenn die Abfrage kompiliert wird, und ihr Wert ändert sich bei jedem Aufruf. In der Praxis GETDATE() wird nur einmal für jeden Ausdruck ausgewertet, in dem er verwendet wird – zur Ausführungszeit statt Kompilierzeit . Microsoft setzt jedoch rand() und getdate() in eine spezielle Kategorie, genannt nicht-deterministische Laufzeitkonstantenfunktionen. Im Gegensatz dazu springt Postgres nicht durch solche Reifen, sondern ruft nur Funktionen auf, die einen konstanten Wert haben, wenn sie als "stable" ausgeführt werden.

Trotz Martin Smiths Kommentar ist die SQL Server-Dokumentation zu diesem Thema einfach nicht explizit -- GETDATE() wird sowohl als "nicht deterministisch" als auch als "nicht deterministische Laufzeitkonstante" beschrieben, aber dieser Begriff wird nicht wirklich erklärt. An der einen Stelle, an der ich den Begriff gefunden habe, heißt es beispielsweise in den nächsten Zeilen in der Dokumentation, keine nichtdeterministischen Funktionen in Unterabfragen zu verwenden. Das wäre ein dummer Ratschlag für "nichtdeterministische Laufzeitkonstante".

Ich würde vorschlagen, eine Variable mit einer Konstante auch innerhalb einer Abfrage zu verwenden, damit Sie einen konsistenten Wert haben. Dies macht auch die Absicht ziemlich klar:Sie möchten einen einzelnen Wert in der Abfrage. Innerhalb einer einzelnen Abfrage können Sie Folgendes tun:

select . . . 
from (select getdate() as now) params cross join
     . . . 

Eigentlich ist dies ein Vorschlag, der sollte nur einmal in der Abfrage auswerten, aber es kann Ausnahmen geben. Verwirrung entsteht, weil getdate() gibt den gleichen Wert in allen verschiedenen Zeilen zurück – aber es kann unterschiedliche Werte in verschiedenen Spalten zurückgeben. Jeder Ausdruck mit getdate() wird unabhängig ausgewertet. Dies ist offensichtlich, wenn Sie Folgendes ausführen:

select rand(), rand()
from (values (1), (2), (3)) v(x);

Innerhalb einer gespeicherten Prozedur möchten Sie einen einzelnen Wert in einer Variablen haben. Was passiert, wenn die gespeicherte Prozedur nach Mitternacht ausgeführt wird und sich das Datum ändert? Welche Auswirkungen hat das auf die Ergebnisse?

In Bezug auf die Leistung vermute ich, dass die Suche nach Datum/Uhrzeit minimal ist und für eine Abfrage einmal pro Ausdruck auftritt, wenn die Abfrage ausgeführt wird. Dies sollte nicht wirklich ein Leistungsproblem sein, sondern eher ein Problem der Codekonsistenz.