Ich habe eine Abfrage, die immer nach einem Status filtert. Gibt es einen Leistungsvorteil auf eine dieser Arten gegenüber der anderen?
(Dies steht im Zusammenhang mit einer Ad-hoc-Abfrage. Der Datentyp von UserStatus ist int.)
...
AND UserStatus = 1
...
oder
DECLARE @userStatus int = 1
...
AND UserStatus = @userStatus
...
(ps bitte rede nicht darüber, wie sich Parameter und Literale unterscheiden, wenn die Werte unbekannt sind / sich ändern, das ist ein anderes Thema)
sql-server
performance
sql-server-2016
JeremyWeir
quelle
quelle
Antworten:
In Ordnung, vorausgesetzt, Sie sprechen von einer lokalen Variablen, die von einer Abfrage in SSMS ausgeführt wird, da nichts anderes angegeben wurde. Selbst wenn Sie denselben Wert für den Wert verwenden, den
AND UserStatus = @userStatus
Sie im Literal verwendenAND UserStatus = 1
würden, sehen Sie einen Unterschied in Ihrem Ausführungsplan aufgrund der Art und Weise, wie die Kardinalitätsschätzung generiert wird.Wenn Sie einen Literalwert verwenden, geht SQL Server zum Histogramm für diese Tabelle und zeigt an, wo dieser Wert in den Bereichsschlüssel passt. Die darauf gesammelte Schätzung führt zu einem von zwei Szenarien.
HISTOGRAM DIRECT HIT Im Wesentlichen bedeutet dies, dass
RANGE_HI_KEY
für diesen bestimmten Literalwert in Ihrer Abfrage ein Wert (oberer Spaltenwert für jeden Schritt im Histogramm) vorhanden ist. Daher entspricht die Schätzung der AnzahlEQ_ROWS
( Anzahl der Zeilen, deren Wert dem entsprichtRANGE_HI_KEY
) im Histogramm . Dies bedeutet, dass Ihre Schätzung die Anzahl der Zeilen ist, die diesem Wert entsprechen, basierend auf der letzten Aktualisierung der Statistiken.HISTOGRAMM INTRA-STEP HIT Dies ist der Fall, wenn der Wert in einem Bereich zwischen zwei
RANGE_HI_KEY
Werten liegt. Wenn Ihr Literalwert zwischen diesem Bereich liegt, wird er durchRANGE_ROWS
(Anzahl der Zeilen zwischen zwei Histogrammschritten),DINSTINCT_RANGE
(Anzahl der unterschiedlichen Werte innerhalb dieses Histogrammschritts) undAVG_RANGE_ROWS
(RANGE_ROWS
/DISTINCT_RANGE_ROWS
) berechnet und gibt Ihnen Ihre Schätzung.Wenn Sie jedoch mit einer lokalen Variablen ausgeführt werden, werden diese Werte nicht mehr im Histogramm angezeigt, da
@Variable
sie zur Laufzeit nicht bekannt sind.Für weitere Informationen zu diesem Thema empfehle ich, dieses Whitepaper von Joe Sack zu lesen .
DICHTE-VEKTOR Wenn es keinen bestimmten Wert gibt, verwendet SQL Server stattdessen eine Dichte, um die geschätzte Anzahl der für dieses Prädikat zurückgegebenen Zeilen bestimmen zu können. Die Dichte beträgt 1 / die Anzahl der unterschiedlichen Werte in dieser Spalte. Dann ist Ihre Kardinalitätsschätzung Dichte * die Anzahl der Zeilen in der Tabelle.
So lange Rede, kurzer Sinn, nein. Selbst wenn Sie denselben Wert immer wieder mit einer lokalen Variablen ausführen, erhalten Sie aus Gründen, die im Link Eric Provided von Kendra Little näher erläutert werden, nicht dieselben Ergebnisse .
quelle
Dem Optimierer ist ein Literalwert bekannt (damit er die Selektivität basierend auf diesem Wert schätzen kann).
Ein Parameterwert (gespeicherte Prozedur, Funktion) wird zur Ausführungszeit abgehört. Eine nachfolgende Ausführung hat möglicherweise einen anderen Wert, für den der zuvor kompilierte Plan möglicherweise nicht optimal ist.
Für eine Variable ist der Wert dem Optimierer nicht bekannt. Es kann möglicherweise die Dichte anzeigen (im Durchschnitt haben wir so viele Zeilen für einen bestimmten Wert) oder es werden fest verdrahtete Schätzungen verwendet (wie z. B.> 10% Selektivität ergeben, oder wie hoch diese prozentualen Anteile auch sein mögen). .
quelle