Wo finde ich die Ursache des Problems, wenn eine zuvor schnelle SQL-Abfrage langsam ausgeführt wird?


36

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.


Könnten Sie den Abfrageplan (den langsamen) hier teilen
MJH

Antworten:


31

Wenn eine Abfrage, die früher schnell ausgeführt wurde, plötzlich mitten in der Nacht langsam ausgeführt wird und nichts anderes als diese eine Abfrage betroffen ist, wie behebe ich sie dann?

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_statsund sys.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 .

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.

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.

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.

Dies kann leicht getestet werden. SET STATISTICS TIME ONzeigt 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


7

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:

OPTION (MERGE JOIN, HASH JOIN)

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.


1
Der Ausführungsplan verwendet in der Tat einen Join mit verschachtelten Schleifen. Wenn ich den Hinweis wie von Ihnen vorgeschlagen platziere, wird jedoch die folgende Fehlermeldung angezeigt: "Der Abfrageprozessor konnte aufgrund der in dieser Abfrage definierten Hinweise keinen Abfrageplan erstellen. Senden Sie die Abfrage erneut, ohne Hinweise anzugeben und ohne SET FORCEPLAN zu verwenden." Wenn ich natürlich OPTION (LOOP JOIN) hinzufüge, wird ein Ausführungsplan erstellt, aber ich habe immer noch ein Problem damit, dass er langsam läuft. Sind Sie auf dieses Problem gestoßen? Sieht aus wie es denkt, es muss eine Schleife verbinden.

@ Trevor. . . Nein, dieses Problem habe ich noch nicht gesehen. Möglicherweise führt Ihre Abfrage einige Nicht-Equijoins aus (ohne Gleichheitszeichen), und der Optimierer muss dort Joins mit verschachtelten Schleifen verwenden.
Gordon Linoff

3

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: 48PercentForTop


2
Ein Index wird jedoch nicht plötzlich "fehlen". Dies kann zwar die Leistung verbessern, erklärt jedoch nicht das Problem
Fowl

3

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


0

Sie müssen auch überprüfen, ob eine Serversicherung oder ein Archivierungs- / Indexierungsjob ausgeführt wird, wenn in T-SQL \ Procedure Leistungsprobleme auftreten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.