Database
 sql >> Datenbank >  >> RDS >> Database

Der DBCC_OBJECT_METADATA-Latch

In Fortsetzung meiner Artikelserie über Latches werde ich dieses Mal auf den DBCC_OBJECT_METADATA-Latch eingehen und zeigen, wie er unter bestimmten Umständen ein großer Engpass für Konsistenzprüfungen vor SQL Server 2016 sein kann. Das Problem betrifft DBCC CHECKDB, DBCC CHECKTABLE und DBCC CHECKFILEGROUP, aber der Klarheit halber verweise ich für den Rest dieses Beitrags nur auf DBCC CHECKDB.

Sie fragen sich vielleicht, warum ich über ein Problem schreibe, das ältere Versionen betrifft, aber es gibt immer noch eine große Anzahl von SQL Server 2014 und älteren Instanzen da draußen, also ist es ein gültiges Thema für meine Serie.

Ich empfehle Ihnen dringend, den ersten Beitrag in der Serie vor diesem zu lesen, damit Sie über das gesamte allgemeine Hintergrundwissen über Verriegelungen verfügen.

Was ist der DBCC_OBJECT_METADATA-Latch?

Um diesen Latch zu erklären, muss ich ein wenig erklären, wie DBCC CHECKDB funktioniert.

Zu den zahlreichen Konsistenzprüfungen, die DBCC CHECKDB durchführt, gehört auch eine Überprüfung der Korrektheit von Nonclustered-Indizes. Insbesondere stellt DBCC CHECKDB Folgendes sicher:

  1. Für jeden Nonclustered-Index-Datensatz in jedem Nonclustered-Index gibt es genau einen „passenden“ Datensatz in der Basistabelle (entweder ein Heap oder ein Clustered-Index)
  2. Für jeden Datensatz in einer Tabelle gibt es in jedem für die Tabelle definierten Nonclustered-Index genau einen „passenden“ Nonclustered-Index-Datensatz unter Berücksichtigung gefilterter Indizes

Ohne zu sehr in die Details zu gehen, wie dies gemacht wird, konstruiert DBCC CHECKDB für jeden Datensatz in einer Tabelle jeden Nonclustered-Index-Datensatz, der für jeden Nonclustered-Index vorhanden sein sollte, und stellt sicher, dass der konstruierte Nonclustered-Index-Datensatz genau mit dem tatsächlichen übereinstimmt Nonclustered-Index-Datensatz. Wenn der Nonclustered-Index eine berechnete Spalte enthält (entweder als Teil des Nonclustered-Indexschlüssels oder als INCLUDEd-Spalte), muss DBCC CHECKDB den berechneten Spaltenwert ermitteln, der beim Erstellen der Indexdatensätze verwendet werden soll.

Sowie die Nonclustered-Index-Korrektheitsprüfungen, wenn ein fortbestehender vorhanden ist berechnete Spalte in der Definition einer Tabelle, dann muss DBCC CHECKDB für jeden Datensatz in der Tabelle überprüfen, ob der persistente Wert korrekt ist, unabhängig davon, ob diese Spalte Teil eines nicht gruppierten Indexes ist oder nicht.

Wie ermittelt es also die berechneten Spaltenwerte?

Der Abfrageprozessor stellt einen Mechanismus zum Berechnen berechneter Spaltenwerte bereit, der als "Ausdrucksauswerter" bezeichnet wird. DBCC CHECKDB ruft diese Funktion auf und stellt die entsprechenden Metadateninformationen und den Datensatz bereit, und die Ausdrucksauswertung verwendet die gespeicherte Definition der berechneten Spalte in den Metadaten und die Werte aus dem Datensatz und gibt den Wert der berechneten Spalte für DBCC CHECKDB zur Verwendung zurück . Die interne Funktionsweise der Ausdrucksauswertung liegt außerhalb der Kontrolle des DBCC-Codes, aber um die Ausdrucksauswertung verwenden zu können, muss zuerst ein Latch erworben werden; den DBCC_OBJECT_METADATA-Latch.

Wie wird der Latch zum Flaschenhals?

Hier ist das Problem:Es gibt nur einen akzeptablen Modus, in dem der DBCC_OBJECT_METADATA-Latch abgerufen werden kann, bevor die Ausdrucksauswertung verwendet wird, und das ist der EX-Modus (exklusiv). Und wie Sie aus dem Intro-Beitrag zur Serie wissen, kann im EX-Modus immer nur ein Thread die Latte halten.

Zusammenführen all dieser Informationen:Wenn eine Datenbank persistente berechnete Spalten oder nicht gruppierte Indizes mit berechneten Spalten enthält, muss der Ausdrucksauswerter verwendet werden. Wenn es sich bei der SQL Server-Edition um Enterprise handelt, kann DBCC CHECKDB Parallelität verwenden und verfügt daher über mehrere Threads, die die verschiedenen Prüfungen durchführen. Und sobald Sie mehrere Threads haben, die versuchen, einen Latch im EX-Modus zu erhalten, wird dieser Latch zu einem Engpass. Wie groß der Engpass wird, hängt davon ab, wie häufig der Ausdrucksauswerter verwendet werden muss. Je mehr persistente berechnete Spalten oder nicht gruppierte Indizes, die berechnete Spalten verwenden, vorhanden sind und je größer die Anzahl der Tabellenzeilen in diesen Tabellen ist, desto mehr Je größer der Engpass wird, desto größer wird der DBCC _OBJECT_METADATA-Latch.

Denken Sie jedoch daran, dass dieser Engpass nur bei SQL Server-Versionen vor SQL Server 2016 auftritt. In SQL Server 2016 hat Microsoft beschlossen, den Engpass zu „beheben“, indem die Überprüfungen von nicht gruppierten Indizes mithilfe berechneter Spalten standardmäßig deaktiviert und nur durchgeführt werden, wenn die WITH Die Option EXTENDED_LOGICAL_CHECKS wird verwendet.

Aufzeigen des Engpasses

Sie können den Engpass einfach selbst reproduzieren, indem Sie DBCC CHECKDB auf einer Datenbank ausführen, die entweder persistente berechnete Spalten oder nicht gruppierte Indizes mit berechneten Spalten enthält, und die von Microsoft bereitgestellte AdventureWorks-Datenbank ist ein hervorragendes Beispiel. Hier können Sie Sicherungen von AdventureWorks für Ihre Version von SQL Server herunterladen. Ich habe einige Tests mit einer AdventureWorks2014-Datenbank auf einer SQL Server 2014-Instanz (auf einem Dell R720 mit 32 Kernen) durchgeführt und die Datenbank mithilfe von Jonathans Skripts auf einige hundert GB erweitert.

Als ich DBCC CHECKDB ausführte, wobei der Server MAXDOP auf 0 gesetzt war, dauerte die Ausführung mehr als 5 Stunden. Der Wartetyp LATCH_EX machte etwa 30 % der Wartezeiten aus, wobei jede Wartezeit knapp 1 Millisekunde dauerte, und 99 % der LATCH_EX-Wartezeiten entfielen auf den DBCC_OBJECT_METADATA-Latch.

Ich habe mit dem folgenden Code nach Nonclustered-Indizes gesucht, die berechnete Spalten enthalten:

SELECT
      [s].[name] AS [Schema],
      [o].[name] AS [Object],
      [i].[name] AS [Index],
      [c].[name] AS [Column],
      [ic].*
  FROM sys.columns [c]
  JOIN sys.index_columns [ic]
      ON [ic].[object_id] = [c].[object_id]
      AND [ic].[column_id] = [c].[column_id]
  JOIN sys.indexes [i]
      ON [i].[object_id] = [ic].[object_id]
      AND [i].[index_id] = [ic].[index_id]
  JOIN sys.objects [o]
      ON [i].[object_id] = [o].[object_id]
  JOIN sys.schemas [s]
      ON [o].[schema_id] = [s].[schema_id]
  WHERE [c].[is_computed] = 1;

Dieser Code hat sechs Nonclustered-Indizes in der AdventureWorks2014-Datenbank gefunden. Ich habe alle sechs Indizes deaktiviert (mit ALTER INDEX … DISABLE) und DBCC CHECKDB erneut ausgeführt, was in etwa 18 Minuten abgeschlossen war. Der DBCC_OBJECT_METADATA-Latch-Engpass war also ein Hauptfaktor dafür, dass DBCC CHECKDB mehr als 16-mal langsamer lief!

Zusammenfassung

Leider ist das Deaktivieren von nicht gruppierten Indizes mit berechneten Spalten (und das spätere erneute Aktivieren mit ALTER INDEX … REBUILD) die *einzige* Möglichkeit, den DBCC_OBJECT_METADATA-Latch-Engpass in Versionen vor SQL Server 2016 zu entfernen, während alle anderen Funktionen von DBCC erhalten bleiben CHECKDB. Das Deaktivieren von Nonclustered-Indizes ist wahrscheinlich nichts, was Sie in einer Produktionsumgebung tun möchten, es sei denn, Sie haben ein Wartungsfenster ohne Aktivitäten. Das bedeutet, dass Sie diese nicht gruppierten Indizes wahrscheinlich nur dann deaktivieren werden, um den Engpass zu beseitigen, wenn Ihre Konsistenzprüfungen mithilfe der Methode backup-copy-restore-CHECKDB auf einen anderen Server ausgelagert werden.

Eine andere Möglichkeit besteht darin, die Option WITH PHYSICAL_ONLY zu verwenden, wenn Sie DBCC CHECKDB ausführen, aber dann verpassen Sie alle eingehenden logischen Prüfungen, daher bin ich kein großer Fan davon, dies als Lösung zu empfehlen.