Vorwort
Es gibt ein Informationssystem, das ich verwalte. Das System besteht aus folgenden Komponenten:
1. MS SQL Server-Datenbank
2. Serveranwendung
3. Client-Anwendungen
Diese Informationssysteme sind auf mehreren Objekten installiert. Das Informationssystem wird 24 Stunden am Tag von 2 bis 20 Benutzern gleichzeitig an jedem Objekt aktiv genutzt. Daher können Sie die routinemäßige Wartung nicht auf einmal durchführen. Also muss ich die SQL Server-Indexdefragmentierung über den Tag «verteilen», anstatt alle notwendigen fragmentierten Indizes auf einen Schlag zu defragmentieren. Dies gilt auch für andere Vorgänge.
Die Eigenschaft für die automatische Aktualisierung der Statistik wird in den Eigenschaften der Datenbank festgelegt. Außerdem werden die Statistiken auf dem defragmentierten Index aktualisiert.
Problem
Vor ungefähr einem Jahr stieß ich auf das folgende Problem:
Von Zeit zu Zeit liefen alle Abfragen langsam. Bemerkenswerterweise war die Verzögerungszeit zufällig. Es passierte an einem zufälligen Tag bei jedem Objekt. Als ich anfing zu analysieren, wie oft die Verzögerungen auftreten (mithilfe des Profilers), stellte ich außerdem fest, dass sie jeden Tag zu einer zufälligen Zeit auftreten. Benutzer achten nur nicht immer darauf, sondern nehmen sie als einzige zufällige Verzögerung, und dann funktioniert das System wieder schnell.
Das Problem lösen
Ich habe alle langsam laufenden Abfragen überprüft. Das Seltsamste war, dass alle Abfragen zu zufälligen Zeiten langsam liefen, selbst die einfachsten, wie das Abrufen des letzten Datensatzes aus einer Tabelle mit mehreren tausend Zeilen.
Außerdem habe ich die folgenden Schritte ausgeführt:
1. Ich habe die Protokolle von MS SQL Server und Windows Server analysiert, konnte aber die Ursache der Verzögerungen nicht finden.
2. Ich habe Indizes (Fragmentierung etc.) analysiert, fehlende hinzugefügt und unbenutzte entfernt.
3. Ich habe die Abfragen analysiert – einige Abfragen wurden verbessert.
4. Ich habe die Aufgaben im SQL Agent analysiert und konnte die Aufgaben nicht mit dem Verzögerungsproblem in Verbindung bringen.
5. Ich habe die Aufgaben im Taskplaner analysiert und konnte die Aufgaben nicht mit dem Verzögerungsproblem in Verbindung bringen.
6. Profiler zeigte die Ergebnisse, aber nicht die Ursache der Verzögerungen.
7. Ich habe eine Überprüfung auf Deadlocks durchgeführt – es wurden keine langen Blockierungen aufgedeckt.
Infolgedessen verbrachte ich mehr als 3 Monate mit der erfolglosen Suche nach dem Grund für gelegentlich langsam laufende Abfragen. Ich habe jedoch eine interessante Tatsache aufgedeckt – anstelle des Worker-Ausführungsindikators hat sich der Indikator für die verstrichene Wartezeit für alle Abfragen erhöht. Diese Tatsache brachte mich auf die Idee, dass etwas mit den Festplatten nicht stimmt. Ich habe sie überprüft – alles war in Ordnung.
Lösung
Zu meiner Überraschung habe ich versehentlich festgestellt, dass eine Abfrage, die in der Anwendung langsam ausgeführt wurde, in SSMS schnell ausgeführt wurde. Ein Artikel half bei der Lösung des Problems (zumindest schlug er die Idee vor).
Ein Absatz aus dem Artikel:
In der Praxis ist die wichtigste SET-Option ARITHABORT, da der Standardwert für diese Option für Anwendungen und für SQL Server Management Studio unterschiedlich ist. Dies erklärt, warum Sie eine langsam laufende Abfrage in Ihrer Anwendung erkennen und dann eine gute Geschwindigkeit erzielen können, indem Sie sie in SSMS ausführen. Die Anwendung verwendet einen Plan, der für eine Gruppe von Werten erstellt wurde, die von den tatsächlichen korrekten Werten abweicht. Wenn Sie hingegen die Abfrage in SSMS ausführen, ist es sehr wahrscheinlich, dass der Cache noch keinen Ausführungsplan für ARITHABORT ON hat und SQL Server daher einen Plan für Ihre aktuellen Werte erstellt.
Der Unterschied in der Ausführung war auf den Parameter SET ARITHABORT zurückzuführen. Für alle in SSMS ausgeführten Abfragen ist diese Option aktiviert und für Abfragen von außen (von Anwendungen) – deaktiviert. Es kann nicht einmal durch eine einfache Abfrage für Anwendungen aktiviert werden:
SET ARITHABORT ON;
Es folgte eine verrückte Idee – das Löschen des prozeduralen Caches zum Zeitpunkt des Auflegens.
Für die anschließende manuelle Prüfung muss ich vor der Abfrage in SSMS folgende Anweisung schreiben:
SET ARITHABORT OFF;
So simulieren wir den Betrieb der Anwendung. Als die Abfrage längere Zeit ausgeführt wurde, habe ich den prozeduralen Cache geleert. Und das hat immer geholfen. Vor dem Löschen des prozeduralen Caches konnte die Abfrage bis zu 20–30 Sekunden dauern und danach – 0 Sekunden.
Danach habe ich ein weiteres Experiment durchgeführt – den gesamten prozeduralen Cache für die gesamte Datenbank stündlich über den SQL-Agenten gelöscht:
--cleaning the cache by database id DBCC FLUSHPROCINDB (@db_id);
Danach liefen alle Abfragen sehr schnell (weniger als 0,05 Sekunden). Es gab nur einige Vorkommnisse von bis zu 5-10 Sekunden Ausführung, aber die Benutzer bemerkten keine Aufhänger. Außerdem hat die Aktualisierung der Statistik die Ergebnisse nicht verbessert, also habe ich die Statistikaktualisierung deaktiviert.
Nach einigen weiteren Monaten des Studiums entdeckte ich, dass gelegentliche Hänger auftreten, wenn entweder der Cache alles auf dem Server verbraucht und kein freier Speicherplatz mehr vorhanden ist oder wenn ein freier Speicher vorhanden ist, aber weniger als 1 GB RAM oder der MS SQL Server-Dienst belegt den gesamten zugewiesenen Arbeitsspeicher (über den Task-Manager). Aber das zweite Ereignis trat in der gesamten Studie nur zweimal auf.
Tatsache ist, dass buchstäblich alles in den Cache geschrieben wird, während der Cache nicht immer rechtzeitig freigegeben wird. Das Problem mit dem Cache wurde mit dem Programm EmptyStandbyList.exe gelöst.
Ich habe diese Anwendung über den Taskplaner so konfiguriert, dass sie 1 Mal pro Stunde ausgeführt wird. Nach all der geleisteten Arbeit gibt es seit mehr als einem halben Jahr keine Abfragen mehr zu allen Objekten.
Unklar bleiben nur die seltenen Fälle, in denen eine Abfrage einmal im Monat an einem zufälligen Tag und zu einer zufälligen Uhrzeit für 5-10 Sekunden auflegt. Es gab 4 solcher Fälle und nur auf zwei Objekten für ein halbes Jahr, wenn der MS SQL Server-Dienst für kurze Zeit den gesamten zugewiesenen Speicher belegt.
Im Grunde ist es nicht nötig, tiefer zu graben, da die Benutzer keine Aufhänger bemerken und alles gut funktioniert, aber wenn jemand irgendwelche Gedanken hat, bin ich für eine Mitteilung dankbar.
Dieser Artikel wurde geschrieben, um denen zu helfen, die auf solche Probleme stoßen, da ich im Internet keine umfassende Antwort gefunden habe und viel Zeit damit verbracht habe, das Problem zu studieren und die Lösung zu finden.
Siehe auch:
- Implementieren des SQL Server-Leistungsindikators für Abfragen, gespeicherte Prozeduren und Trigger
- Automatisierung der Indexdefragmentierung in der MS SQL Server-Datenbank
Nützliches Tool:
dbForge Query Builder for SQL Server – ermöglicht Benutzern das schnelle und einfache Erstellen komplexer SQL-Abfragen über eine intuitive visuelle Oberfläche ohne manuelles Schreiben von Code.