Um meine kurze Reihe von Artikeln über Latches abzuschließen, werde ich dieses Mal ein paar andere Latches in SQL Server besprechen, die Sie vielleicht gelegentlich sehen, die aber keinen vollständigen Artikel verdienen. Wie üblich empfehle ich Ihnen dringend, den ersten Beitrag der Serie vor diesem zu lesen, damit Sie über das gesamte allgemeine Hintergrundwissen über Latches verfügen.
Der LOG_MANAGER-Latch
Der LOG_MANAGER-Latch wird während einiger Vorgänge, die das Transaktionsprotokoll betreffen, zur Synchronisation verwendet, und es gibt einen LOG_MANAGER-Latch pro Datenbank (da jede Datenbank ihren eigenen Protokollmanager hat). Es kann nur im exklusiven Modus abgerufen werden und kann beim Wachstum der Transaktionsprotokolldatei zu einem Engpass werden. Das Szenario, in dem es als Problem offensichtlich wird, ist:
- Die Protokolldatei enthält einen kleinen Satz für automatisches Wachstum
- Es gibt viele gleichzeitige Verbindungen, die Transaktionsprotokolleinträge generieren
- Die Protokolldatei muss immer größer werden
Wenn der Speicherplatz der Protokolldatei knapp wird, muss sie wachsen. Der erste Thread, der erkennt, dass mehr Protokollspeicherplatz erforderlich ist, ruft den LOG_MANAGER-Latch im EX-Modus ab und fährt damit fort, die Protokolldatei zu vergrößern. Viele andere Threads versuchen weiterhin, Protokolldatensätze zu generieren und in die Warteschlange für den LOG_MANAGER-Latch zu gelangen, damit sie die Protokolldatei vergrößern können. Wenn der erste Thread den Latch freigibt, bekommt der nächste ihn und stellt fest, dass das Protokoll bereits gewachsen ist, lässt es also fallen und fährt fort. Und so weiter und so weiter. Übrigens wird dieses Engpassmuster als Latch-Konvoi bezeichnet .
Sie können sich das als genau den gleichen Engpass vorstellen wie beim FGCB_ADD_REMOVE-Latch, den ich früher in der Serie besprochen habe, aber mit einem Wachstum der Protokolldatei anstelle des Wachstums der Datendatei. Mit dem FGCB_ADD_REMOVE-Latch hat die Instanz jedoch normalerweise die sofortige Dateiinitialisierung aktiviert, sodass das Dateiwachstum sehr schnell ist, aber mit dem LOG_MANAGER-Latch *muss* das Protokoll mit Nullen initialisiert werden, und die Zeit, die in der Latch-Warteschlange verschwendet wird, ist länger .
Die Lösung für diesen Engpass besteht aus drei Teilen:
- Stellen Sie die automatische Vergrößerung der Protokolldatei korrekt ein, damit das Protokoll nicht häufig wächst
- Passen Sie die Größe des Protokolls an die Arbeitslast an, sodass das Protokoll überhaupt nicht wachsen sollte
- Stellen Sie sicher, dass das Protokoll korrekt gelöscht wird, sodass das Protokoll nicht wachsen muss
Wenn diese alle vorhanden sind, sollte der LOG_MANAGER-Latch kein regelmäßiger Engpass sein, und ich werde in meinem Beitrag hier mehr darüber sprechen.
Der ACCESS_METHODS_DATASET_PARENT Latch
Wenn entweder auf einen Heap oder einen Index zugegriffen wird, gibt es intern ein Objekt namens HeapDataSetSession bzw. IndexDataSetSession. Wenn ein paralleler Scan durchgeführt wird, haben die Threads, die die eigentliche Arbeit des Scans erledigen, jeweils einen „untergeordneten“ Datensatz (eine weitere Instanz der beiden gerade beschriebenen Objekte), und der Hauptdatensatz, der den Scan wirklich steuert, wird aufgerufen die „Eltern“.
Wenn einer der Scan-Worker-Threads die Menge der zu scannenden Zeilen erschöpft hat, muss er einen neuen Bereich abrufen, indem er auf das übergeordnete Dataset zugreift, was bedeutet, dass der Latch ACCESS_METHODS_DATASET_PARENT im exklusiven Modus abgerufen wird. Dies mag zwar wie ein Engpass erscheinen, ist es aber nicht wirklich, und Sie können nichts tun, um zu verhindern, dass die Threads, die einen parallelen Scan durchführen, gelegentlich ein LATCH_EX-Warten auf diesen Latch anzeigen.
Die Frage, die Sie sich stellen sollten, lautet:Soll diese Abfrage überhaupt einen parallelen Scan durchführen? Es ist durchaus möglich, dass etwas passiert ist, um den Abfrageplan zu zwingen, einen parallelen Scan einzubeziehen, obwohl dies möglicherweise nicht die effizienteste Methode für die Ausführung der Abfrage ist. Beispiele für Dinge, die dazu führen können, dass ein Plan in einen parallelen Scan geändert wird, sind:
- Veraltete Statistiken
- Ein fehlender oder gelöschter Nonclustered-Index
- Neuer Code, der aufgrund einer impliziten Konvertierung einen Scan erzwingt – ein Datentypkonflikt zwischen einer Spalte und einer Variablen/einem Parameter, der die Verwendung eines nicht gruppierten Indexes ausschließt
- Neuer Code, der einen Scan erzwingt, da Arithmetik für eine Tabellenspalte statt für eine Variable/einen Parameter ausgeführt wird, was wiederum die Verwendung eines nicht gruppierten Indexes ausschließt
- Es kommt zu einem Datenwachstum und ein Scan ist wirklich der effizienteste Plan
Oder es könnte sein, dass diese Abfrage einen Scan erfordert, in diesem Fall wartet LATCH_EX darauf, dass ACCESS_METHODS_DATASET_PARENT nur Teil Ihrer Umgebung sind.
Der ACCESS_METHODS_HOBT_VIRTUAL_ROOT-Latch
Jede Instanz dieses Latches schützt einen Eintrag in den Speicher-Engine-Metadaten für einen B-Baum, insbesondere die Seiten-ID der Stammseite des B-Baums (die Seite oben im Dreieck, die wir im Allgemeinen als Index betrachten). . Ich sage ausdrücklich B-Baum und nicht indexieren , da ein Index mehrere Partitionen haben kann, von denen jede einen B-Tree hat (im Wesentlichen ein Teil des Gesamtindex, aber mit Schlüsselbeschränkungen für niedrige und hohe Werte).
Jedes Mal, wenn ein Thread einen B-Baum durchlaufen muss, muss er auf der Stammseite beginnen und sich bis zur Blattebene vorarbeiten. Um die Metadaten zu lesen, die die Seiten-ID der Stammseite enthalten, muss der Thread den ACCESS_METHODS_HOBT_VIRTUAL_ROOT-Latch im SH-Modus erwerben, um sicherzustellen, dass sich die Seiten-ID nicht gerade ändert. Wenn ein Thread die Seiten-ID der Stammseite ändern muss, muss er den Latch im EX-Modus abrufen.
Warum sollte sich die Stammseite eines B-Baums jemals ändern? Wenn die Anzahl der Indexdatensätze in der Stammseite zunimmt, füllt sie sich schließlich und es kommt zu einer Seitenteilung. Wenn dies geschieht, werden die aktuelle Stammseite und die Seite, in die sie aufgeteilt wird, zu einer neuen Ebene im B-Baum, und es wird eine brandneue Stammseite mit zwei Indexdatensätzen erstellt, die auf die alte Stammseite und die Seite darauf zeigen aufgeteilt in. Die neue Stammseiten-ID muss in die Metadaten eingegeben werden, damit der Latch im EX-Modus erfasst wird. Dies passiert ein paar Mal schnell, wenn ein Index in einer leeren Tabelle mit Einfügungen gefüllt wird, aber Sie werden es nicht als anhaltendes Problem mit Leistungsengpässen sehen.
Zusammenfassung
Wie Sie sicher aus dieser Serie mitbekommen haben, erfordert das Verständnis von Latches und Latch-Engpässen, etwas mehr darüber zu wissen, was in der Storage Engine vor sich geht, als für die allgemeine Wartestatistikanalyse.
Normalerweise rate ich den Leuten, *nicht* mit der Leistungsfehlersuche zu beginnen, indem sie sich Latch-Statistiken ansehen (über sys.dm_os_latch_stats ), sondern immer mit Wartestatistiken zu beginnen (siehe meinen Beitrag hier) und sich nur mit Latches zu befassen, wenn LATCH_EX oder LATCH_SH zu den oberen Handvoll Wartevorgängen auf der SQL Server-Instanz gehören.
Wenn Sie Fragen zu Latches haben, können Sie mir gerne eine Nachricht schreiben.