Einführung
Der SQL Server-Abfrageoptimierer nutzt während der Abfragekompilierung Statistiken, um den optimalen Abfrageplan zu bestimmen. Wenn der Optimierer feststellt, dass eine Statistik aufgrund zu vieler Änderungen an einer Tabelle veraltet ist, aktualisiert er die Statistik standardmäßig sofort, bevor die Abfragekompilierung fortgesetzt werden kann (nur die benötigten Statistiken, nicht alle Statistiken für die Tabelle). .
Beachten Sie, dass „zu viele“ nicht spezifisch ist, da es je nach Version variiert und ob das Trace-Flag 2371 aktiviert ist – siehe den Abschnitt AUTO_UPDATE_STATISTICS auf dieser Seite für Details.
Das Problem mit synchronen Statistikaktualisierungen
Das synchrone Aktualisieren von Statistiken vor der Kompilierung führt offensichtlich zu einer Verzögerung und führt dazu, dass die Kompilierung und Ausführung der Abfrage länger dauert. Wie groß die Verzögerung ist, hängt von mehreren Faktoren ab, darunter:
- Wie viele an der Abfrage beteiligte Tabellen haben den Schwellenwert „zu viele Änderungen“ erreicht
- Wie viele Statistiken für jede dieser Tabellen aktualisiert werden müssen, weil sie für die Kompilierung benötigt werden
- Wie viele Zeilen gibt es in den beteiligten Tabellen
- Die Optionen, die angegeben wurden, als jede Statistik erstellt wurde (z. B. FULLSCAN und PERSIST_SAMPLE_PERCENT=ON)
Daher kann es zu einer scheinbar zufälligen Verzögerung kommen, die in einigen Szenarien zu Problemen führen kann, insbesondere wenn für eine Anwendung ein sehr niedriges Abfrage-Timeout festgelegt ist.
Vermeiden synchroner Statistikaktualisierungen
Es gibt verschiedene Möglichkeiten, synchrone Statistikaktualisierungen zu vermeiden, z. B.:
- Setzen Sie AUTO_UPDATE_STATISTICS auf OFF, wodurch alle automatischen Aktualisierungen deaktiviert werden und Sie Ihre eigene Statistikverwaltung durchführen müssen, um die Möglichkeit suboptimaler Abfragepläne aufgrund veralteter Statistiken zu vermeiden.
- Setzen von AUTO_UPDATE_STATISTICS_ASYNC auf ON, so dass der Optimierer, wenn er bemerkt, dass eine Statistik aktualisiert werden muss, mit der Kompilierung fortfährt und eine Hintergrundaufgabe die Statistik etwas später aktualisiert. Dies funktioniert nur, wenn Sie auch AUTO_UPDATE_STATISTICS auf ON gesetzt haben.
- Führen Sie eine regelmäßige Statistikwartung durch, damit überhaupt keine automatischen synchronen oder asynchronen Statistikaktualisierungen stattfinden.
In der SQL Server-Community wird viel darüber diskutiert, ob asynchrone Statistikaktualisierungen aktiviert werden sollen. Ich habe meine liebe Frau Kimberly L. Tripp nach ihrer Meinung gefragt, und sie empfiehlt immer, sie zu aktivieren, und sie hat mehr über Statistiken vergessen, als ich jemals wissen werde, also glaube ich ihr. ☺
Verfolgen von synchronen Statistikaktualisierungen
Es gab noch nie eine offensichtliche Möglichkeit festzustellen, ob eine Abfrage lange gedauert hat, weil sie auf eine synchrone Statistikaktualisierung gewartet hat. *Nachdem* die Statistikaktualisierung abgeschlossen war, konnten Sie feststellen, ob Sie bereits eine erweiterte Ereignissitzung hatten und auf die auto_stats achteten Ereignis und Filterung nach Async Spalte auf 0 gesetzt. Diese Spalte in der Ereignisausgabe wurde jedoch nur in SQL Server 2017 hinzugefügt, und Sie müssten auch eine Aktion konfigurieren, die etwas erfasst, um die betreffende Abfrage zu identifizieren.
Jetzt gibt es in SQL Server 2019 den Wartetyp WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE, und auf den ersten Blick scheint es Ihnen leicht zu sein, zu sehen, ob eine Abfrage auf ein synchrones Statistikupdate wartet, indem Sie einfach in sys.dm_os_waiting_tasks nachsehen, was die Abfrage gerade ist Warten auf.
Leider ist das nicht der Fall.
Der Begriff „warten“ ist hier etwas irreführend, da der Thread in diesem Fall nicht wirklich wartet. Dieser neue Wartetyp ist ein Beispiel für ein sogenanntes „präemptives“ Warten, bei dem der Thread in einen Modus wechselt, in dem er auf dem Prozessor verbleibt, bis er seine Arbeit beendet hat. Die meisten präventiven Wartezeiten treten auf, wenn ein Thread einen Aufruf außerhalb von SQL Server durchführt (z. B. um Sicherheitsinformationen von einem Domänencontroller zu erhalten), aber manchmal tut ein Thread etwas innerhalb von SQL Server und muss es abschließen, bevor er möglicherweise gezwungen wird, den Prozessor freizugeben weil sein 4-ms-Thread-Quantum abgelaufen ist. Keines dieser Dinge ist das, was hier passiert. In diesem Fall registriert der Thread den Beginn eines präemptiven Wartens mit dem neuen Wartetyp und führt dann die Statistikaktualisierung durch, wobei wahrscheinlich andere *echte* Wartezeiten wie PAGEIOLATCH_SH auf dem Weg dorthin entstehen. Erst wenn die Statistikaktualisierung abgeschlossen ist, endet das präventive Warten und wird in den Messwerten der Wartestatistik berücksichtigt.
Warum ist das eine große Sache? Nun, die DMV sys.dm_os_waiting_tasks zeigt die Wartetypen für alle Threads, die *wirklich* warten, d. h. auf der Warteaufgabenliste eines Schedulers, also wenn der Aktualisierungsthread für synchrone Statistiken nicht auf WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE wartet, diesen Wartetyp wird nicht in der Ausgabe des DMV angezeigt. Der neue Wartetyp kann nicht verwendet werden, um zu sehen, ob eine Abfrage gerade auf eine Statistikaktualisierung wartet.
Sie können sich das leicht selbst beweisen, indem Sie Folgendes tun:
- Erstellen Sie eine Tabelle mit einigen hunderttausend Zeilen
- Erstellen Sie eine Statistik für eine Tabellenspalte und geben Sie FULLSCAN und PERSIST_SAMPLE_PERCENT =ON als Optionen an, wodurch erzwungen wird, dass die gesamte Tabelle jedes Mal gelesen wird, wenn die Statistik aktualisiert wird
- Zwanzigtausend Zeilen aktualisieren
- Überprüfen Sie die Datenbank und führen Sie DBCC DROPCLEANBUFFERS aus
- Führen Sie eine SELECT-Anweisung mit einer WHERE-Klausel für die Spalte mit der von Ihnen erstellten Statistik durch
- Suchen Sie in der DMV von sys.dm_os_waiting_tasks nach der Sitzungs-ID von SELECT, und Sie werden sehen, dass es wahrscheinlich auf PAGEIOLATCH_SH wartet, während die Statistikaktualisierung die Tabelle durchliest
Abgesehen von dieser Enttäuschung gibt es einen Trick, um zu sehen, ob eine Abfrage auf ein synchrones Statistik-Update wartet. Wenn eine Statistikaktualisierung stattfindet, wird ein Befehl namens STATMAN ausgeführt, und Sie können dies in der Ausgabe von sys.dm_exec_requests sehen :der Status wird „angehalten“ (obwohl der Thread läuft, wie oben beschrieben), und der Befehl lautet „SELECT (STATMAN).“
Was nützt der neue Wartetyp?
Obwohl der neue Wartetyp nicht als sofortige Möglichkeit verwendet werden kann, um mitzuteilen, dass eine Abfrage auf eine synchrone Statistikaktualisierung wartet, wissen Sie, dass einige Abfragen in der Arbeitslast möglicherweise unter diesen Verzögerungen leiden, wenn er in Ihrer regulären Wartestatistikanalyse angezeigt wird . Aber das ist für mich die Grenze des Nutzens. Sofern die durchschnittliche Wartezeit nicht als relevanter Prozentsatz Ihrer durchschnittlichen Abfrageausführungszeit angezeigt wird oder Sie ständig Wartezeiten über kurze Zeiträume erfassen, um eine ordnungsgemäße Analyse zu ermöglichen, wissen Sie nicht sicher, ob ein Problem vorliegt.
Dies ist ein Wartetyp, bei dem die Wartezeit stark variieren kann, abhängig von den Faktoren, die ich zuvor erwähnt habe. Daher würde ich nur das Vorhandensein dieses Wartetyps verwenden, um auf potenzielle Probleme aufmerksam gemacht zu werden, und ich möchte eine erweiterte Ereignissitzung wie oben beschrieben implementieren, um Instanzen synchroner Statistikaktualisierungen zu erfassen, um zu sehen, ob ihre Dauer lang genug ist, um sie zu verdienen einige Korrekturmaßnahmen ergreifen.
Zusammenfassung
Ich bin mir nicht sicher, ob das Hinzufügen des Wartetyps WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE etwas daran ändern wird, ob Leute asynchrone Statistikaktualisierungen konfigurieren oder einfach die gesamte Statistikpflege selbst durchführen, aber zumindest können Sie jetzt feststellen, ob Abfragen auf synchrone Statistiken warten aktualisieren und weitere Maßnahmen ergreifen.
Bis zum nächsten Mal, viel Spaß bei der Fehlerbehebung!