Jedes Mal, wenn ich auf diese Art von Abfragen stoße, frage ich mich, wie SQL Server das schaffen würde. Wenn ich einen Abfragetyp ausführe, für den eine Berechnung erforderlich ist, und diesen Wert dann an mehreren Stellen verwende, z. B. in select
und order by
, wird SQL Server ihn für jede Zeile zweimal berechnen oder zwischengespeichert? Wie funktioniert dies außerdem mit benutzerdefinierten Funktionen?
Beispiele:
SELECT CompanyId, Count(*)
FROM Sales
ORDER BY Count(*) desc
SELECT Geom.BufferWithTolerance(@radius, 0.01, 0).STEnvelope().STPointN(1).STX, Geom.BufferWithTolerance(@radius, 0.01, 0).STEnvelope().STPointN(1).STY
FROM Table
SELECT Id, udf.MyFunction(Id)
FROM Table
ORDER BY udf.MyFunction(Id)
Gibt es eine Möglichkeit, es effizienter zu gestalten, oder ist SQL Server intelligent genug, um es für mich zu handhaben?
sql-server
Jonas Stawski
quelle
quelle
SELECT RAND() FROM Sales order by RAND()
- dies wird nur einmal ausgewertet, da es sowohl nicht deterministisch als auch eine Laufzeitkonstante ist.Antworten:
Das SQL Server-Abfrageoptimierungsprogramm kann wiederholt berechnete Werte in einem einzigen Compute Scalar-Operator kombinieren. Ob dies der Fall ist oder nicht, hängt von der Kalkulation des Abfrageplans und den Eigenschaften des berechneten Werts ab. Wie erwartet wird dies nicht für berechnete Werte durchgeführt, die nicht deterministisch sind, was einige Ausnahmen wie z
RAND()
. Dies wird auch nicht für benutzerdefinierte Funktionen ausgeführt.Ich werde mit einem benutzerdefinierten Funktionsbeispiel beginnen. Hier ist ein hervorragendes Beispiel für eine benutzerdefinierte Funktion:
Ich möchte auch eine Tabelle erstellen und 100 Zeilen einfügen:
Die
dbo.NULL_FUNCTION
Funktion ist deterministisch. Wie oft wird es für die folgende Abfrage ausgeführt?Basierend auf dem Abfrageplan wird dies einmal für jede Zeile oder 100 Mal ausgeführt:
In SQL Server 2016 wurde die DMV sys.dm_exec_function_stats eingeführt . Wir können Schnappschüsse dieser DMV machen, um zu sehen, wie oft eine UDF von einer Abfrage ausgeführt wird.
Das Ergebnis ist 100, daher wurde die Funktion 100 Mal ausgeführt.
Versuchen wir eine andere einfache Abfrage:
Der Abfrageplan schlägt vor, dass die Funktion 200 Mal ausgeführt wird:
Die Ergebnisse von
sys.dm_exec_function_stats
legen nahe, dass die Funktion 200 Mal ausgeführt wurde.Beachten Sie, dass Sie den Abfrageplan nicht immer verwenden können, um herauszufinden, wie oft ein Berechnungsskalar ausgeführt wird. Das folgende Zitat stammt aus " Skalare, Ausdrücke und Leistung des Ausführungsplans berechnen ":
Versuchen wir ein anderes Beispiel. Für die folgende Abfrage würde ich hoffen, dass die UDF einmal berechnet wird:
Der Abfrageplan schlägt vor, dass er einmal berechnet wird:
Die DMV enthüllt jedoch die Wahrheit. Der Berechnungsskalar wird verschoben, bis er benötigt wird, was sich im Join-Operator befindet. Es wird 100 mal ausgewertet.
Sie haben auch gefragt, was Sie tun können, um den Optimierer zu ermutigen, den gleichen Ausdruck nicht mehrmals neu zu berechnen. Das Beste, was Sie tun können, ist zu vermeiden, skalare UDFs in Ihrem Code zu verwenden. Diese haben eine Reihe von Leistungsproblemen außerhalb dieser Frage, darunter das Aufblasen von Speicherzuweisungen, das Erzwingen der Ausführung der gesamten Abfrage
MAXDOP 1
, schlechte Kardinalitätsschätzungen und die zusätzliche CPU-Auslastung. Wenn Sie eine UDF verwenden müssen und der Wert dieser UDF eine Konstante ist, können Sie sie außerhalb der Abfrage berechnen und in eine lokale Variable einfügen.Bei Abfragen ohne UDFs können Sie vermeiden, Ausdrücke zu schreiben, die dasselbe Ergebnis zurückgeben, aber nicht genau auf dieselbe Weise eingegeben werden. Für dieses nächste Beispiel verwende ich die öffentlich verfügbare AdventureworksDW2016CTP3-Datenbank, aber wirklich jede Datenbank reicht aus. Wie oft wird
COUNT(*)
für diese Abfrage berechnet?Für diese Abfrage können wir dies anhand des Operators Hash Match (Aggregat) herausfinden.
Das
COUNT(*)
wird einmal für jeden eindeutigen Wert von berechnetOrderDateKey
. Das Einbeziehen derORDER BY
Klausel führt nicht dazu, dass sie zweimal berechnet wird. Den Ausführungsplan sehen Sie hier .Stellen Sie sich nun eine Abfrage vor, die genau dieselben Ergebnisse liefert, aber anders geschrieben ist:
Das Abfrageoptimierungsprogramm ist nicht intelligent genug, um sie zu kombinieren. Daher wird zusätzliche Arbeit geleistet:
quelle