Hintergrund
Ich habe eine Abfrage für SQL Server 2008 R2, die ungefähr 12 verschiedene "Tabellen" verknüpft und / oder links verknüpft. Die Datenbank ist mit vielen Tabellen über 50 Millionen Zeilen und ungefähr 300 verschiedenen Tabellen ziemlich groß. Es ist für ein großes Unternehmen, das 10 Lager im ganzen Land hat. Alle Lagerhäuser lesen und schreiben in die Datenbank. Es ist also ziemlich groß und ziemlich beschäftigt.
Die Abfrage, mit der ich Probleme habe, sieht ungefähr so aus:
select t1.something, t2.something, etc.
from Table1 t1
inner join Table2 t2 on t1.id = t2.t1id
left outer join (select * from table 3) t3 on t3.t1id = t1.t1id
[etc]...
where t1.something = 123
Beachten Sie, dass sich einer der Joins in einer nicht korrelierten Unterabfrage befindet.
Das Problem ist, dass ab heute Morgen, ohne dass Änderungen (die ich oder jemand aus meinem Team kennen) am System vorgenommen wurden, die Abfrage, deren Ausführung normalerweise etwa 2 Minuten dauert, anderthalb Stunden in Anspruch nimmt lief überhaupt. Der Rest der Datenbank summt prima mit. Ich habe diese Abfrage aus dem Sproc genommen, in dem sie normalerweise ausgeführt wird, und ich habe sie in SSMS mit fest codierten Parametervariablen mit derselben Langsamkeit ausgeführt.
Das Seltsame ist, dass, wenn ich die nicht korrelierte Unterabfrage nehme und sie in eine temporäre Tabelle wirfe und dann diese anstelle der Unterabfrage verwende, die Abfrage einwandfrei ausgeführt wird. Auch (und das ist das seltsamste für mich), wenn ich diesen Code am Ende der Abfrage anhänge, läuft die Abfrage großartig:
and t.name like '%'
Ich bin aus diesen kleinen Experimenten (möglicherweise falsch) zu dem Schluss gekommen, dass der Grund für die Verlangsamung darin liegt, wie der zwischengespeicherte Ausführungsplan von SQL eingerichtet ist. Wenn die Abfrage ein wenig anders ist, muss ein neuer Ausführungsplan erstellt werden.
Meine Frage lautet: Wenn eine Abfrage, die früher plötzlich schnell lief, mitten in der Nacht langsam ausgeführt wird und nichts anderes als diese eine Abfrage betroffen ist, wie behebe ich sie und wie verhindere ich, dass sie in Zukunft ausgeführt wird ? Woher weiß ich, was SQL intern tut, um es so langsam zu machen? (Wenn die fehlerhafte Abfrage ausgeführt wird, kann ich den Ausführungsplan abrufen, aber er wird nicht ausgeführt. Vielleicht gibt mir der erwartete Ausführungsplan etwas?) Wie halte ich SQL davon ab, wirklich beschissene Ausführungspläne für eine gute Idee zu halten, wenn dieses Problem mit dem Ausführungsplan zusammenhängt?
Dies ist auch kein Problem beim Parameter-Sniffing. Ich habe das schon einmal gesehen, und das ist es nicht, denn selbst wenn ich die Variablen in SSMS hart codiere, bekomme ich immer noch eine langsame Leistung.
Antworten:
Sie können zunächst prüfen, ob sich der Ausführungsplan noch im Cache befindet. Überprüfen Sie
sys.dm_exec_query_stats
,sys.dm_exec_procedure_stats
undsys.dm_exec_cached_plans
. Wenn der fehlerhafte Ausführungsplan immer noch zwischengespeichert ist, können Sie ihn analysieren und die Ausführungsstatistiken überprüfen. Die Ausführungsstatistiken enthalten Informationen wie logische Lesevorgänge, CPU-Zeit und Ausführungszeit. Diese können aussagekräftige Hinweise auf das Problem geben (z. B. Large Scan vs. Blocking). Eine Erläuterung zur Interpretation der Daten finden Sie unter Ermitteln von Problemabfragen .Ich bin nicht überzeugt. Das Festcodieren von Variablen in SSMS beweist nicht, dass der frühere Ausführungsplan nicht mit einer verzerrten Eingabe kompiliert wurde. Bitte lesen Sie Parameter Sniffing, Embedding und die RECOMPILE-Optionen für einen sehr guten Artikel zum Thema. Langsam in der Anwendung, schnell in SSMS? Das Verstehen von Leistungsmysterien ist eine weitere hervorragende Referenz.
Dies kann leicht getestet werden.
SET STATISTICS TIME ON
zeigt Ihnen die Kompilierungs- und Ausführungszeit an. SQL Server: Statistik- Leistungsindikatoren zeigen auch an, ob die Kompilierung ein Problem darstellt (ehrlich gesagt halte ich es für unwahrscheinlich).Es gibt jedoch etwas Ähnliches, das Sie möglicherweise treffen: das Abfrage-Grant-Gate. Weitere Informationen finden Sie unter Grundlegendes zur Speicherzuweisung für SQL Server . Wenn Ihre Abfrage zu einem Zeitpunkt, an dem kein Speicher verfügbar ist, eine große Bewilligung anfordert, muss sie warten, und für die Anwendung wird alles als "langsame Ausführung" angezeigt. Wenn Sie die Warteinfo-Statistiken analysieren , sehen Sie , ob dies der Fall ist.
Eine allgemeinere Erläuterung der zu messenden und zu suchenden Elemente finden Sie unter Analysieren der SQL Server-Leistung
quelle
Dies ist ein Fluch, wenn komplexe Abfragen in SQL Server ausgeführt werden. Zum Glück kommt es nicht so oft vor.
Sehen Sie sich den Abfrageplan für die Abfrage an (wenn sie langsam ausgeführt wird). Ich vermute, Sie werden einen Nested-Loop-Join finden, der ein- oder mehrmals in Tabellen ohne Indizes für den Join auftritt. Das verlangsamt die Dinge wirklich. Zum schnellen Vorlauf kann dies mit einem Hinweis behoben werden. Fügen Sie am Ende der Abfrage Folgendes hinzu:
Dies hat dieses Problem für mich in der Vergangenheit im Allgemeinen behoben.
Was möglicherweise passiert ist, dass geringfügige Änderungen an der Tabelle (oder an der Verfügbarkeit von temporärem Speicherplatz) dazu führen, dass die SQL-Optimierung einen langsameren Verknüpfungsalgorithmus bevorzugt. Dies kann sehr subtil und sehr plötzlich sein. Wenn Sie eine temporäre Tabelle erstellen, verfügt das Optimierungsprogramm über weitere Informationen zur Tabelle (z. B. über deren Größe), sodass ein besserer Plan erstellt werden kann.
quelle
Normalerweise ist es ein fehlender Index, der diese Art von Problem verursacht.
Normalerweise führe ich die Abfrage mit SQL Management Studio aus und aktiviere "Aktuellen Ausführungsplan einbeziehen (STRG + M)", um herauszufinden, welcher Join den größten Prozentsatz aufweist.
Die Anwendung konzentriert sich nicht auf den Engpass, aber Sie können ihn "schnell" finden, wenn Sie nur das Ergebnis betrachten.
Beispiel hier:
quelle
Ich habe vor kurzem dasselbe Problem erlebt, das mich auf diese Seite gebracht hat.
@MartinSmith war gerade dabei, als er die Aktualisierung Ihrer Statistiken und die Erläuterung des Plans empfahl. Ich möchte hinzufügen, dass Sie auch versuchen sollten, einen Blick auf laufende Jobs / Abfragen zu werfen, die zu Sperren führen und dadurch die Antwortzeit verlangsamen können.
In meinem Fall war der Täter das Sammeln von Tabellenstatistiken. Aus irgendeinem Grund wurde es in dem Fenster, das es haben sollte, nicht fertiggestellt und lief weiter, als die Benutzer fortgefahren waren. Ich fand den Prozess, brachte ihn zum Erliegen und die Abfragen reagierten erneut.
Ich hoffe das hilft jemand anderem
quelle
Sie müssen auch überprüfen, ob eine Serversicherung oder ein Archivierungs- / Indexierungsjob ausgeführt wird, wenn in T-SQL \ Procedure Leistungsprobleme auftreten.
quelle