Besserer Ausführungsplan, wenn der Parameter in der lokalen Variablen gespeichert ist

8

Ich habe zwei gespeicherte Prozeduren. Dieser ist unglaublich schnell (~ 2 Sekunden)

CREATE PROCEDURE [schema].[Test_fast]
   @week date
AS
BEGIN

    declare @myweek date = @week

    select distinct serial 
    from [schema].[tEventlog]         as e
    join [schema].tEventlogSourceName as s on s.ID = e.FKSourceName
    where s.SourceName = 'source_name'
        and (e.EventCode = 1 or e.EventCode = 9)
        and cast(@myweek as datetime2(3)) <= [Date] 
        and [Date] < dateadd(day, 7, cast(@myweek as datetime2(3)))    
END

Und dieser läuft langsam (~ 2 Stunden):

create PROCEDURE [schema].[Test_slow]
   @week date
AS
BEGIN

    select distinct serial 
    from [schema].[tEventlog]         as e
    join [schema].tEventlogSourceName as s on s.ID = e.FKSourceName
    where s.SourceName = 'source_name'
        and (e.EventCode = 1 or e.EventCode = 9)
        and cast(@week as datetime2(3)) <= [Date] 
        and [Date] < dateadd(day, 7, cast(@week as datetime2(3)))
END

Der einzige wirkliche Unterschied ist die Zeile (unter Verwendung der lokalen Variablen @myweek):

declare @myweek date = @week

Hier sind die Ausführungspläne. Der erste Plan stammt aus [Schema]. [Test_fast] und der zweite aus [Schema]. [Test_slow]:

Geben Sie hier die Bildbeschreibung ein

Meine Frage lautet: Warum erhält SQL Server 2012 einen viel besseren Ausführungsplan (schneller), wenn ich den Parameter in einer lokalen Variablen speichere und dann diese lokale Variable verwende. Ist etwas mit der Statistik oder den Indizes kaputt? (Ich frage mich auch, warum der zweite Ausführungsplan keine parallele Ausführung verwendet).

UPDATE :

Ich gebe den 2 SPs den gleichen Parameter und starte sie zur gleichen Zeit (fast 2s Zeitunterschied). Dies ist keine automatische Aktualisierung der Statistik in dieser Datenbank.

Beispiel:

EXEC    [schema].[Test_fast]
        @week = '2016-02-08'

EXEC    [schema].[Test_slow]
        @week = '2016-02-08'

Hier ist der Ausführungsplan:

https://gist.github.com/anonymous/6e404f896d9613c2061a#file-sp_execution_plan-sqlplan

Eine zusätzliche Aktualisierung des Index hat ebenfalls keine Auswirkung.

Leon
quelle

Antworten:

16

Die Verwendung lokaler Variablen verhindert das Abhören von Parameterwerten, sodass Abfragen basierend auf durchschnittlichen Verteilungsstatistiken kompiliert werden . Dies war die Abhilfe für einige Arten von Parameterempfindlichkeitsproblem vor OPTION (OPTIMIZE FOR UNKNOWN)und Trace - Flag 4136 zur Verfügung steht .

Nach dem bereitgestellten Ausführungsplan ist genau dies in Ihrem Fall geschehen.

Wenn eine lokale Variable verwendet wird, kann der Wert in der Variablen nicht abgehört werden:

Kein Schnüffeln

Beachten Sie das leere "Kompilierter Wert". Der Abfrageoptimierer schätzt eine höhere Anzahl von Zeilen basierend auf der durchschnittlichen Verteilung der Werte in der Spalte Datum (oder möglicherweise einer vollständigen Schätzung), die zum parallelen Plan führt.

Wenn der Parameter der gespeicherten Prozedur direkt verwendet wird, wird der Wert von @week abgehört:

Schnüffelte

Der Optimierer schätzt die Anzahl der Zeilen, die mit den Abfrageprädikaten übereinstimmen, anhand des Werts '2016-02-08', der eingesteckt ist in:

and cast(@week as datetime2(3)) <= [Date] 
and [Date] < dateadd(day, 7, cast(@week as datetime2(3)))

Es wird eine Schätzung von einer Zeile erstellt, die zur Auswahl eines seriellen Plans mit der Schlüsselsuche führt. Die obigen Prädikate sind für die Kardinalitätsschätzung nicht sehr geeignet, daher ist die 1-Zeilen-Schätzung möglicherweise nicht sehr genau. Sie könnten versuchen, das Ablaufverfolgungsflag 4199 zu aktivieren, es gibt jedoch keine Garantie dafür, dass sich die Schätzung verbessert.

Weitere Details finden Sie unter:

Parameter Sniffing, Embedding und die RECOMPILEOptionen

Im Allgemeinen ist es auch möglich, dass der erste Lauf der gespeicherten Prozedur mit einem sehr selektiven Wert für @week erfolgt, wobei nur eine geringe Anzahl von Zeilen erwartet wird. Eine weitere mögliche Ursache für Probleme tritt auf, wenn beim ersten Aufruf ein sehr aktueller Wert von @week verwendet wird, bevor die Statistiken aktualisiert wurden, um diesen Wertebereich abzudecken (dies ist das aufsteigende Schlüsselproblem ).

Ein sehr selektiver Sniffed-Wert für @week kann dazu führen, dass das Abfrageoptimierungsprogramm einen nicht parallelen Plan mit einer Indexsuche und einer Schlüsselsuche auswählt. Dieser Plan wird zur erneuten Verwendung für zukünftige Ausführungen der Prozedur mit unterschiedlichen Parameterwerten zwischengespeichert. Wenn bei einer späteren Ausführung (mit einem anderen Wert für @week) viel mehr Zeilen als ursprünglich ausgewählt werden, ist die Leistung des Plans wahrscheinlich schlecht, da die Suche nach Suchen und Schlüsseln keine gute Strategie mehr ist.

Paul White 9
quelle