Gibt es einen Unterschied zwischen einem Prädikat, das einen Literalwert oder einen Parameterwert verwendet, wenn dieser Wert immer gleich ist?

7

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)

JeremyWeir
quelle
1
Liegt dies im Kontext oder in einer gespeicherten Prozedur oder in Ad-hoc-T-SQL? Könnten Sie bitte Ihre SQL Server-Version als Tag hinzufügen?
George.Palacios
@ George.Palacios Danke, ich habe die Frage aktualisiert. Ich würde gerne mehr darüber erfahren, warum das zwischen Ad-hoc und Sproc wichtig ist.
JeremyWeir
@JeremyWeir sollte es egal sein, ob sich die Werte ändern oder nicht. Wenn Sie eine lokale Variable anstelle eines Literals verwenden, erhalten Sie eine Schätzung basierend auf der Anzahl der Zeilen in einer Tabelle, anstatt das Histogramm zu verwenden, um Ihre Kardinalitätsschätzung zu berechnen.
Zane

Antworten:

11

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 = @userStatusSie im Literal verwenden AND UserStatus = 1wü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_KEYfü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 Anzahl EQ_ROWS( Anzahl der Zeilen, deren Wert dem entspricht RANGE_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_KEYWerten liegt. Wenn Ihr Literalwert zwischen diesem Bereich liegt, wird er durch RANGE_ROWS(Anzahl der Zeilen zwischen zwei Histogrammschritten), DINSTINCT_RANGE(Anzahl der unterschiedlichen Werte innerhalb dieses Histogrammschritts) und AVG_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 @Variablesie 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 .

Zane
quelle
Ich habe eine leichte Korrektur hinzugefügt. Fühlen Sie sich frei, ein Rollback durchzuführen, wenn es nicht beschreibt, was Sie gemeint haben.
John aka hot2use
Sieht gut aus Mann.
Zane
7

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). .

Tibor Karaszi
quelle
Wenn sich der Wert also nie ändert, verhält sich ein Literal anders als ein Parameter?
JeremyWeir
1
Da der Parameter abgehört wird, verhält er sich genauso wie das Literal, vorausgesetzt, Sie haben immer den gleichen Wert. Aber eine Variable ist eine ganz andere Sache!
Tibor Karaszi
Verstanden, gibt es also einen Unterschied zwischen der lokalen Variablen, die als parametrisierter Wert verwendet wird, und einem Sproc-Parameter, der als parametrisierter Wert verwendet wird?
JeremyWeir
3
@JeremyWeir: Ja, deshalb hat Erik vorgeschlagen, den obigen Artikel von Brent Ozar zu lesen .
Andriy M