Unterschiedlicher Ausführungsplan bei der Ausführung von Anweisung direkt und von Stored Procedure
-
05-07-2019 - |
Frage
Während eine neue Abfrage, bei der Arbeit zu entwickeln ich es geschrieben habe und profilierte sie in SQL Query Analyzer. Die Abfrage ausführt wirklich gut ohne Tabellen-Scans, aber wenn ich es in einer gespeicherten Prozedur verkapselt die Leistung war schrecklich. Als ich im Ausführungsplan sah konnte ich sehen, dass SQL Server einen anderen Plan aufgenommen, die einen Tabellenscan statt einem Index auf TableB suchen verwendet (ich habe gezwungen worden, um die Tabellen- und Spaltennamen ein wenig, aber keiner der Abfragelogik zu verschleiern geändert hat).
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 bekomme die folgende Trace-Statistik
Event Class Duration CPU Reads Writes SQL:StmtCompleted 75 41 7 0
Und wenn ich die Abfrage als gespeicherte Prozedur mit dem folgenden Befehl ausführen
DECLARE @ShopId int
SELECT @ShopId = 1
EXEC spStats_GetSalesStatsByHour @ShopId
Ich bekomme die folgende Trace-Statistik
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 SQL Server verursacht einen schlechteren Ausführungsplan, nur weil die Anweisung als eine gespeicherte Prozedur ausgeführt wird holen?
Wir sind zur Zeit laufen auf SQL Server 2000
Lösung
Dies hat in der Regel etwas mit dem Parameter Sniffing zu tun. Es kann sehr frustrierend sein, zu beschäftigen. 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 verwendet werden:
alter procedure p_myproc (@p1 int) as
declare @p1_copy int;
set @p1_copy = @p1;
Und dann verwenden @ p1_copy in der Abfrage. Scheint lächerlich, aber es funktioniert.
Überprüfen Sie meine letzte Frage zum gleichen Thema:
Warum hat der SqlServer Optimierer so verwirrt erhalten mit Parameter?
Andere Tipps
Ja - ich hatte auch den auf Oracle DB 11g gesehen - gleiche Abfrage lief schnell auf 2 Knoten DB-Servers in SQL-Eingabeaufforderung, aber wenn aus dem Paket nennt es hing buchstäblich bis
!hatte den gemeinsamen Pool löschen identisches Verhalten zu bekommen. Grund einig Job / script ausgeführt wurde, die älter hatte in der Bibliothek Cache / Speicher gesperrt Kopie auf einem Knoten mit minderwertigem Ausführungsplan