Ich versuche, ein Problem mit SQL Server 2000 zu verstehen. Wir sind eine Website mit moderaten Transaktionen und haben einen gespeicherten Prozess, sp_GetCurrentTransactions
der eine Kunden- ID und zwei Daten akzeptiert.
Jetzt kann diese Abfrage je nach Datum und Kunde einen Wert zwischen null und 1000 Zeilen zurückgeben.
Das Problem: Was wir erlebt haben, ist, dass wir plötzlich eine Reihe von Fehlern (normalerweise Execution Timeout Expired
oder ähnlich) für einen bestimmten Client erhalten, während sie versuchen, diesen gespeicherten Prozess auszuführen. Wir untersuchen die Abfrage, führen sie in SSMS aus und stellen fest, dass sie 30 Sekunden dauert. Also kompilieren wir den gespeicherten Prozess neu und -bang- läuft jetzt in 300ms.
Ich habe mit unserem DBA darüber gesprochen. Er hat mir gesagt, dass die Datenbank einen Abfrageplan erstellt hat, als wir den gespeicherten Prozess erstellt haben. Er sagte, es sei ein guter Plan für diesen Parametersatz, aber wenn Sie einen bestimmten Parametersatz darauf anwenden, wird der Plan nicht der beste Plan für diese Daten sein, und Sie werden sehen, dass er langsam abläuft.
Die Optionen, die mir angeboten werden, sind das Verschieben der Problemabfrage von einem gespeicherten Prozess in dynamisches SQL, dessen Ausführungsplan bei jedem Durchlauf erstellt wird.
Dies fühlt sich wie ein Schritt zurück zu mir an und ich fühle, dass es einen Weg geben muss, dies zu umgehen. Gibt es eine andere Möglichkeit, mit diesem Problem umzugehen?
Alle Antworten sind willkommen.
quelle
Antworten:
Dieses Problem wird als Parameter-Sniffing bezeichnet.
In späteren Versionen von SQL Server stehen Ihnen weitere Optionen zur Verfügung, wie z. B.
OPTION (RECOMPILE)
oderOPTIMIZE FOR
Hinweise.Sie können versuchen, Variablen in der gespeicherten Prozedur zu deklarieren, den Variablen Parameterwerte zuzuweisen und die Variablen anstelle der Parameter zu verwenden, so als würden Sie die meiste Zeit einen einigermaßen zufriedenstellenden Plan erhalten.
Normalerweise sind die katastrophalsten Pläne diejenigen, die für Parameter mit sehr hoher Selektivität kompiliert wurden, jedoch mit Parametern mit geringer Selektivität ausgeführt wurden.
Angenommen, der generierte Plan ist mit diesem Ansatz robuster und für alle Parameterwerte zufriedenstellend, dann besteht der Vorteil dieses Ansatzes gegenüber dem von JNK vorgeschlagenen darin, dass nicht für jeden Aufruf Kompilierungskosten anfallen.
Der Nachteil ist, dass bei einigen Ausführungen die Laufzeit möglicherweise länger ist als bei einem speziell auf diese Parameterwerte zugeschnittenen Plan, sodass ein Kompromiss zwischen Kompilierungszeit und Ausführungszeit besteht.
quelle
Anstatt dynamisches SQL zu verwenden, können Sie Ihre Proc-Aufrufe jederzeit folgendermaßen ändern:
EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE
Die
WITH RECOMPILE
Truppen (Sie haben es erraten!) Kompilieren den Ausführungsplan jedes Mal neu, wenn er ausgeführt wird.Sie können
WITH RECOMPILE
in die Definition des gespeicherten Prozesses auch Folgendes einbeziehen:quelle
Sie könnten auch versuchen, für die Datenbank zu entscheiden, welchen Plan Sie verwenden möchten, obwohl Sie ein wenig mit dem Optimierer kämpfen würden, sodass er spröder ist, als Sie hoffen.
Die Technik ist folgende: Zerlegen Sie die gespeicherte Prozedur in zwei, eine für einen Parametersatz und eine für einen anderen. Fügen Sie jeweils where-Klauseln hinzu, sodass sie alle möglichen Fälle abdecken. Sehen Sie sich die Abfragepläne an - einer sollte für einen Parametersatz optimiert werden, der andere für den anderen. Möglicherweise müssen Sie an der Abfrage basteln, um dies zu erreichen. Andernfalls ist dies für Ihre Abfrage möglicherweise nicht möglich. In diesem Fall funktioniert dieser Ansatz nicht.
Lassen Sie nun Ihre ursprüngliche gespeicherte Prozedur die Parameterwerte überprüfen und an die entsprechende der beiden gespeicherten Prozeduren aus dem vorherigen Absatz senden.
Dies kann funktionieren, aber es ist eine Art Hack, den Optimierer zu zwingen, effektiver für Ihre Abfrage zu arbeiten. Wie bei allen derartigen Hacks könnte dies in zukünftigen Versionen der Datenbank unnötig sein oder sogar die Situation verschlimmern. Selbst wenn es funktioniert, müssen Sie sich entscheiden, ob es sich lohnt.
quelle
Sie können auch versuchen
SET FORCEPLAN
, Hinweise zu indizieren.http://msdn.microsoft.com/en-us/library/ms188344.aspx
Grundsätzlich können Sie auswählen, in welcher Reihenfolge der Join ausgeführt werden soll.
Sie können Indexhinweise haben, um sicherzustellen, dass SQL Server die richtigen Indizes verwendet.
quelle
Hmmm ... wenn wir uns nur auf diese eine gespeicherte Prozedur konzentrieren, wäre ich überrascht, dass die Verwendung des zwischengespeicherten Ausführungsplans das Problem verursacht, das Sie sehen. Ich möchte den Ausführungsplan der gespeicherten Prozedur mit einer Reihe von Parametern für den Kunden und die beiden Daten anzeigen. Ich frage mich, ob ein spezifischerer Index hilfreich wäre -> wie zum Beispiel auf customerId und nur die beiden Daten?
quelle
Plötzlich nachlassende Leistung klingt nach einem ineffizienten Abfrageplan, der wahrscheinlich aufgrund fehlender Statistiken erstellt wird. Führen Sie einen SQL Server-Profiler mit den festgelegten Ereigniskategorien "Fehler und Warnungen" aus und prüfen Sie, ob Warnungen zu fehlenden Statistiken angezeigt werden.
Möglicherweise fehlt Ihnen auch ein Index, oder Sie müssen die Indizes defragmentieren, da sie möglicherweise zu fragmentiert sind, als dass SQL Server sie verwenden könnte. Dies führt zu der Annahme, dass ein Tabellenscan weniger E / A-Vorgänge verursacht.
@JNK gibt einen wichtigen Hinweis zu gespeicherten Prozessen - diese werden im Voraus kompiliert und der Abfrageplan wird zusammen mit der gespeicherten Prozedur gespeichert.
Ich bin nicht unbedingt mit WITH RECOMPILE einverstanden, da Sie dann den Vorteil verlieren, dass der Abfrageplan gespeichert und wiederverwendet wird. In einigen Fällen ist dies erforderlich - dh, wenn sich Ihre Verteilungsstatistiken in den zugrunde liegenden Tabellen zwischen den Aufrufen stark unterscheiden. Sobald die Daten in den Tabellen jedoch ausgereift sind, ändert sich die Verteilung der Daten innerhalb der Tabellen geringfügig.
Also, um zusammenzufassen:
quelle