2013-06-10 7 views
5

Ich habe eine Ansicht, die schnell läuft (< 1 s), wenn Sie einen Wert in der Angabe, wo Klausel:T-SQL Wählen Sie aus Sicht viel langsamer mit variabler

SELECT * 
FROM vwPayments 
WHERE AccountId = 8155 

Execution plan for first query

... aber läuft langsam (~ 3s), wenn dieser Wert eine Variable ist:

DECLARE @AccountId BIGINT = 8155 

SELECT * 
FROM vwPayments 
WHERE AccountId = @AccountId 

Execution plan for second query

Warum ist der Ausführungsplan für die zweite Abfrage anders? Warum läuft es so viel langsamer?

Antwort

1

Kurz gesagt, die statistische Analyse, die der Abfrageoptimierer verwendet, um den besten Plan auszuwählen, wählt eine Suche aus, wenn der Wert ein bekannter Wert ist, und kann Statistiken und einen Scan verwenden, wenn der Wert nicht bekannt ist. Es wählt einen Scan in der zweiten Auswahl aus, da der Plan kompiliert wird, bevor der Wert der WHERE-Klausel bekannt ist.

Während ich in diesem speziellen Fall nur selten den Abfrageanalysator mit dem Befehl boosten kann, können Sie einen forceseek Hinweis oder andere Abfragehinweise verwenden, um die Engine zu überschreiben. Seien Sie sich jedoch bewusst, dass es eine viel bessere Lösung ist, mit der Hilfe des Motors einen optimalen Plan zu finden.

Ich habe eine schnelle Google und fand eine decent article, die in das Konzept der lokalen Variablen eingreift, die Abfragepläne tiefer beeinflussen.

+1

forceseek hat gut funktioniert – Domenic

+0

Seien Sie einfach vorsichtig damit, Sie können in viele Schwierigkeiten geraten, wenn Sie versuchen, intelligenter als die Abfrage-Engine zu sein. – RThomas

0

Es könnte Parameter Sniffing sein. Versuchen Sie Folgendes und tun Sie Folgendes - ich nehme an, dass es in einer gespeicherten Prozedur ist?

 
DECLARE @Local_AccountId BIGINT = @AccountId 

SELECT * 
FROM vwPayments 
WHERE AccountId = @Local_AccountId 

Einzelheiten über Parameter Sniffing, können Sie diesen Link betrachten: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

Prüfen Sie, ob die Ergebnisse unterschiedlich sind. Ich habe dieses Problem mehrmals, vor allem, wenn die Abfrage während Peaks viel aufgerufen wird, und der Ausführungspuffer, der im Off-Peak erstellt wurde.

Eine andere Option, aber in Ihrem Fall sollten Sie "WITH RECOMPILE" nicht zu einer Prozedurdefinition hinzufügen. Dies würde dazu führen, dass die Prozedur jedes Mal neu kompiliert wird, wenn sie aufgerufen wird. Anzeigen http://www.techrepublic.com/article/understanding-sql-servers-with-recompile-option/5662581

+0

es ist nicht in einer gespeicherten Prozedur funktioniert. – Domenic

+0

Wenn Sie eine Dummy-Variable wie vorgeschlagen erstellen, sind die Ergebnisse unterschiedlich? Der Ausführungsplan sollte immer in diesem Fall bleiben und Sie sollten eine konstante Zeit für die Ausführung dieser Abfrage haben. – Mez

0

Ist AccountID eigentlich ein BIGINT Datentyp? Könnte eine Konvertierung verlangsamt werden?

+0

Es ist ein BIGINT-Typ. – Domenic

4

Im ersten Fall war der Parameterwert beim Kompilieren der Anweisung bekannt. Der Optimierer verwendete das Statistikhistogramm, um den besten Plan für diesen bestimmten Parameterwert zu erzeugen.

Wenn Sie die lokale Variable definiert haben, konnte der SQL Server den Parameterwert nicht verwenden, um den optimalen Wert zu finden. Da der Parameterwert zur Kompilierzeit unbekannt ist, berechnet der Optimierer eine geschätzte Anzahl von Zeilen basierend auf einer "gleichmäßigen Verteilung". Der Optimierer hat einen Plan entwickelt, der für jeden möglichen Eingangsparameterwert "gut genug" wäre.

Ein weiterer interessanter Artikel, der Ihren Fall fast genau beschreibt, finden Sie here.

0

Ich denke @souplex machte einen sehr guten Punkt

Grundsätzlich im ersten Fall ist es nur eine Zahl und einfach für das System zu verstehen, während die zweite eine Variable ist, die jedes Mal, bedeutet, dass das System müssen die sehr finden Wert davon und macht die Prüfung für jede Aussage, die für mich eine andere Methode ist

1
DECLARE @Local_AccountId BIGINT = @AccountId 

SELECT * 
FROM vwPayments 
WHERE AccountId = @Local_AccountId 
OPTION(RECOMPILE) 

es

Verwandte Themen