2009-01-07 4 views
6

Während ich eine neue Abfrage bei der Arbeit entwickelte, schrieb ich sie und profilierte sie in SQL Query Analyzer. Die Abfrage war sehr gut ohne Tabellen-Scans, aber wenn ich es in einer gespeicherten Prozedur gekapselt hatte, war die Leistung schrecklich. Als ich den Ausführungsplan betrachtete, konnte ich sehen, dass SQL Server einen anderen Plan ausgewählt hatte, der einen Tabellenscan anstelle eines Indexsuchlaufs auf TableB verwendete (ich war gezwungen, die Tabellen- und Spaltennamen ein wenig zu verschleiern, aber keine der Abfragelogik hat sich verändert).Unterschiedlicher Ausführungsplan beim Ausführen der Anweisung direkt und aus der gespeicherten Prozedur

Hier ist die Abfrage

SELECT  
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)) AS Day, 
    DATEPART(hh, TableA.Created) AS [Hour], 
    SUM(TableB.Quantity) AS Quantity, 
    SUM(TableB.Amount) AS Amount 
FROM 
    TableA 
    INNER JOIN TableB ON TableA.BID = TableB.ID 
WHERE  
    (TableA.ShopId = @ShopId) 
GROUP BY 
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)), 
    DATEPART(hh, TableA.Created) 
ORDER BY 
    DATEPART(hh, TableA.Created) 

Wenn ich die Abfrage ausführen „raw“ Ich erhalte die folgenden Trace-Statistik

 
Event Class   Duration CPU Reads Writes 
SQL:StmtCompleted 75  41  7  0 

Und wenn ich ausführen, um die Abfrage als eine gespeicherte Prozedur mit dem folgenden Befehl

Ich bekomme die folgenden Spur Statistiken

 
Event Class   Duration CPU Reads Writes 
SQL:StmtCompleted 222  10  48  0 

ich auch das gleiche Ergebnis, wenn ich die Abfrage in einer nvarchar speichern und ausführen Sp_executesql wie folgt aus (es führt wie die sproc)

DECLARE @SQL nvarchar(2000) 
SET @SQL = 'SELECT DATEADD(dd, ...' 
exec sp_executesql @SQL 

Die gespeicherte Prozedur enthält nichts außer für die select-Anweisung oben. Was würde dazu führen, dass SQL Server einen untergeordneten Ausführungsplan auswählt, nur weil die Anweisung als gespeicherte Prozedur ausgeführt wird?

Wir laufen zur Zeit auf SQL Server 2000

Antwort

13

Dies hat in der Regel etwas mit dem Parameter Sniffing zu tun. Es kann sehr frustrierend sein, damit umzugehen. Manchmal kann es durch erneute Kompilierung der gespeicherten Prozedur gelöst werden, und manchmal kann man sogar eine doppelte Variable innerhalb der gespeicherten Prozedur wie folgt verwenden:

alter procedure p_myproc (@p1 int) as 
declare @p1_copy int; 
set @p1_copy = @p1; 

Und verwenden Sie dann @ p1_copy in der Abfrage. Scheint lächerlich, aber es funktioniert.

Überprüfen Sie meine letzte Frage zum gleichen Thema:

Why does the SqlServer optimizer get so confused with parameters?

+1

Danke mann, das hat den Trick Kudos für die rötlich schnelle Antwort! –

-1

Ja - ich hatte auch das auf Oracle DB 11g gesehen - gleiche Abfrage auf 2 Knoten DB-Server an SQL-Eingabeaufforderung schnell lief ABER wenn es vom Paket angerufen wurde, hat es buchstäblich aufgelegt!

mussten den freigegebenen Pool löschen, um identisches Verhalten zu erhalten: Grund war, dass ein Job/Skript ausgeführt wurde, bei dem ältere Kopie im Bibliothekscache/-speicher auf einem Knoten mit unterem Ausführungsplan gesperrt war.

Verwandte Themen