Mir sind die Parameter-Sniffing-Probleme bekannt, die mit gespeicherten Prozeduren verbunden sind, die mit einem Prädikat wie dem folgenden geschrieben wurden:
CREATE PROCEDURE [dbo].[Get] @Parameter INT = NULL AS BEGIN;
SELECT [Field] FROM [dbo].[Table]
WHERE [Field] = @Parameter
OR @Parameter IS NULL;
END;
Abhängig vom Wert des Parameters Scalar oder NULL bei der ersten Ausführung wird ein Plan zwischengespeichert, der für den entgegengesetzten Wert wahrscheinlich nicht optimal ist.
Angenommen, [Feld] ist skalar und der Clustering-Index für eine Tabelle. Was sind die Vor- und Nachteile der folgenden Ansätze zum Schreiben einer gespeicherten Prozedur (en) zur Unterstützung der Abfrage:
Bedingte Auswahl in derselben gespeicherten Prozedur
CREATE PROCEDURE [dbo].[Get] @Parameter INT = NULL AS BEGIN;
IF(@Parameter IS NOT NULL) BEGIN;
SELECT [Field]
FROM [dbo].[Table]
WHERE [Field] = @Parameter;
END;
ELSE BEGIN;
SELECT [Field]
FROM [dbo].[Table];
END;
END;
Dynamisches SQL innerhalb der gespeicherten Prozedur
CREATE PROCEDURE [dbo].[Get] @Parameter INT = NULL AS BEGIN;
DECLARE @sql NVARCHAR(MAX) = N'';
SET @sql += N'SELECT [Field]'
SET @sql += N'FROM [dbo].[Table]';
IF(@Parameter IS NOT NULL) BEGIN;
@sql += N'WHERE [Field] = @Parameter';
END;
SET @sql += N';';
EXEC sp_executesql @sql N'@Parameter INT', @Parameter;
END;
Getrennte gespeicherte Prozeduren
CREATE PROCEDURE [dbo].[Get] @Parameter INT = NULL AS BEGIN;
SELECT [Field]
FROM [dbo].[Table]
WHERE [Field] = @Parameter;
END;
CREATE PROCEDURE [dbo].[GetAll] AS BEGIN;
SELECT [Field]
FROM [dbo].[Table];
END;
sql-server
execution-plan
plan-cache
M. Jacobson
quelle
quelle
=NULL
werden 0 Zeilen zurückgegeben. Obwohl oft Null-Zeilen-Schätzungen auf 1 aufgerundet werdenAntworten:
Sie sind alle ausgezeichnet. Ja wirklich. Sie alle haben die gleiche Auswirkung, wenn zwei Pläne im Cache gespeichert sind.
Wenn Sie mehr und mehr Parameter erhalten, werden Sie feststellen, dass die Option Dynamic SQL am klarsten ist, auch wenn sie für Anfänger beängstigender erscheint.
Wenn dies eine Funktion wäre, würde ich vorschlagen, Optionen mit mehreren Anweisungen zu vermeiden, damit die Qualitätssicherung ihre Aufgaben besser erledigen kann.
quelle
Wenn Sie sich in einem relativ neuen SQL Server-Build befinden, können Sie auch eine andere Option in Betracht ziehen
Jedes Mal auf Kosten einer Kompilierung einen optimalen Plan für den Laufzeitwert erhalten.
Ihre Option "Bedingte Auswahl" ist weiterhin anfällig für Parameter-Sniffing. Wenn die Prozedur zum ersten Mal ausgeführt wird, wenn sie
@Parameter
null ist,[Field] = @Parameter
schätzt der Zweig mit dem Prädikat 1 Zeilen (aufgerundet von der für ein=NULL
Prädikat erwarteten 0 ).In dem speziellen Beispiel in Ihrer Frage, in dem Sie eine einzelne Spalte auswählen und das ist dieselbe Spalte, nach der Sie filtern, ist es unwahrscheinlich, dass dies ein Problem darstellt, dies kann jedoch in anderen Fällen der Fall sein.
Beispiel: Im folgenden Beispiel werden beim ersten Aufruf
[dbo].[Get] 1
333.731 logische Lesevorgänge ausgeführt, da ein unangemessener Plan mit Schlüsselsuchen ausgewählt wird. Wenn der Plan aus dem Cache entfernt und mit1
zuerst übergeben neu kompiliert wird, fallen die logischen Lesevorgänge auf 4.330quelle
Basierend auf den vorherigen Antworten und Kommentaren von Aaron Bertrand, Martin Smith und Rob Farley. Ich wollte für jeden Ansatz eine Pro / Contra-Liste zusammenstellen, einschließlich des zusätzlichen Ansatzes OPTION (RECOMPILE):
Bedingte Auswahl in derselben gespeicherten Prozedur
Aus Martin Smiths Antwort:
Dynamisches SQL innerhalb der gespeicherten Prozedur
Von Rob Farley:
Getrennte gespeicherte Prozeduren
OPTION (RECOMPILE)
Von Martin Smith:
Mein persönlicher Imbiss
Wenn es keine signifikante Abweichung in der Ergebnismenge mit unterschiedlichen Skalarwerten von @Parameter gibt, ist Dynamic SQL ein Top-Performer, hat den geringsten Systemaufwand und ist im Vergleich zu OPTION (RECOMPILE) in Bezug auf den Verwaltungsaufwand nur unwesentlich schlechter. In komplexeren Szenarien, in denen Abweichungen im Parameterwert zu erheblichen Änderungen der Ergebnismengen führen können, ist die Verwendung von Dynamic SQL mit bedingtem Einschluss oder Ausschluss von OPTION (RECOMPILE) die beste Gesamtleistung. Hier ist ein Link zu Aaron Bertrands Artikel, der den Ansatz detailliert beschreibt: https://blogs.sentryone.com/aaronbertrand/backtobasics-updated-kitchen-sink-example/
quelle