Entschlüsselung von Key und Page WaitResource in Deadlocks und Sperren

Wenn Sie den Blockierungsbericht (blocked process report) verwenden oder die Deadlock-Grafiken, die von SQL Server bereitgestellt werden, gelegentlich sammeln, werden Sie irgendwann auf solche Dinge stoßen:

waitresource="PAGE: 6:3:70133"

waitresource="KEY: 6:72057594041991168 (ce52f92a058c)"

Manchmal enthält das riesige XML, das Sie analysieren, mehr Informationen (die Deadlock-Grafiken enthalten eine Liste von Ressourcen, die helfen, die Namen des Objekts und des Indexes herauszufinden), aber nicht immer.

Dieser Text hilft Ihnen, sie zu entschlüsseln.

Alle Informationen, die hier vorhanden sind, gibt es im Internet an verschiedenen Stellen, sie sind nur sehr verstreut! Ich möchte alles zusammenbringen – von DBCC PAGE über hobt_id bis hin zu den undocumented %%physloc%% und %%lockres%% Funktionen.

Zuerst sprechen wir über Wartezeiten bei PAGE-Sperren und danach über KEY-Sperren.

1) waitresource="PAGE: 6:3:70133" = Datenbank_Id: FileId: PageNumber

Wenn Ihre Anfrage auf eine PAGE-Sperre wartet, gibt SQL Server Ihnen die Adresse dieser Seite.

Wenn wir "PAGE: 6:3:70133" aufschlüsseln, erhalten wir:

  • database_id = 6
  • data_file_id = 3
  • page_number = 70133

1.1) Entschlüsseln des database_id

Lassen Sie uns den Namen der Datenbank mit der Abfrage finden:

SELECT 
    name 
FROM sys.databases 
WHERE database_id=6;
GO

Das ist öffentlich zugänglich DB WideWorldImporters auf meinem SQL Server.

1.2) Suchen des Namens der Datendatei – falls es Sie interessiert

Wir werden data_file_id im nächsten Schritt verwenden, um den Namen der Tabelle zu finden. Sie können einfach zum nächsten Schritt übergehen, aber wenn Sie am Namen der Datei interessiert sind, können Sie ihn finden, indem Sie die Abfrage im Kontext der gefundenen DB ausführen und data_file_id in diese Abfrage einsetzen:

USE WideWorldImporters;
GO
SELECT 
    name, 
    physical_name
FROM sys.database_files
WHERE file_id = 3;
GO

In der DB WideWorldImporters ist dies eine Datei mit dem Namen WWI_UserData und sie wurde bei mir in C:MSSQLDATAWideWorldImporters_UserData.ndf wiederhergestellt. (Ups, Sie haben mich dabei erwischt, wie ich die Dateien auf dem Systemlaufwerk abgelegt habe! Nein! Das war peinlich).

1.3) Erhalten des Objekt-Namens aus DBCC PAGE

Jetzt wissen wir, dass die Seite #70133 in der Datendatei 3 zur DB WorldWideImporters gehört. Wir können den Inhalt dieser Seite mit dem undocumented DBCC PAGE und dem Trace-Flag 3604 anschauen.
Hinweis: Ich ziehe es vor, DBCC PAGE auf einer wiederhergestellten Kopie aus einem Backup auf einem anderen Server zu verwenden, da es eine undocumented Funktion ist. In einigen Fällen kann es zu einem Dump führen. (Hinweis des Übersetzers – der Link führt leider ins Leere, aber laut URL dürfte es sich um gefilterte Indizes handeln).

/* This trace flag makes DBCC PAGE output go to our Messages tab
instead of the SQL Server Error Log file */
DBCC TRACEON (3604);
GO
/* DBCC PAGE (DatabaseName, FileNumber, PageNumber, DumpStyle)*/
DBCC PAGE ('WideWorldImporters',3,70133,2);
GO

Wenn Sie zu den Ergebnissen scrollen, können Sie object_id und index_id finden.
Entschlüsselung von Key und Page WaitResource in Deadlocks und Sperren
Fast fertig! Jetzt können Sie die Namen des Schemas und des Index mit dieser Abfrage finden:

USE WideWorldImporters;
GO
SELECT 
    sc.name as schema_name, 
    so.name as object_name, 
    si.name as index_name
FROM sys.objects as so 
JOIN sys.indexes as si on 
    so.object_id=si.object_id
JOIN sys.schemas AS sc on 
    so.schema_id=sc.schema_id
WHERE 
    so.object_id = 94623380
    and si.index_id = 1;
GO

Und so sehen wir, dass das Warten auf die Sperre auf dem Index PK_Sales_OrderLines der Tabelle Sales.OrderLines war.

Hinweis: In SQL Server 2014 und höher können Sie den Objektnamen auch über die undocumented DMO sys.dm_db_database_page_allocations finden. Sie müssen jedoch jede Seite in der DB abfragen, was für große Datenbanken nicht wirklich schön aussieht; deshalb habe ich DBCC PAGE verwendet.

1.4) Kann man die Daten auf der Seite sehen, die blockiert war?

Naja, ja. Aber... sind Sie sich sicher, dass Sie das wirklich brauchen?
Es ist selbst bei kleinen Tabellen langsam. Aber es ist irgendwie cool, also, da Sie bis hierher gelesen haben... lassen Sie uns über %%physloc%% sprechen!

%%physloc%% ist ein undocumented Stück Magie, das die physische ID für jeden Datensatz zurückgibt. Sie können es verwenden %%physloc%% zusammen mit sys.fn_PhysLocFormatter in SQL Server 2008 und höher.

Jetzt, da wir wissen, dass wir eine Sperre auf die Seite in Sales.OrderLines anwenden wollten, können wir alle Daten in dieser Tabelle, die in der Datendatei #3 auf Seite #70133 gespeichert sind, mit dieser Abfrage ansehen:

Use WideWorldImporters;
GO
SELECT 
    sys.fn_PhysLocFormatter (%%physloc%%),
    *
FROM Sales.OrderLines (NOLOCK)
WHERE sys.fn_PhysLocFormatter (%%physloc%%) like '(3:70133%'
GO

Wie ich sagte – es ist selbst bei winzigen Tabellen langsam. Ich habe NOLOCK zur Abfrage hinzugefügt, weil wir sowieso keine Garantien haben, dass die Daten, die wir sehen wollen, genau die gleichen sind, die zum Zeitpunkt der Blockierung vorhanden waren – wir können also ruhig dirty reads durchführen.
Aber hurra, die Abfrage liefert mir genau die 25 Zeilen, um die sich unsere Abfrage gestritten hat
Entschlüsselung von Key und Page WaitResource in Deadlocks und Sperren
Genug von PAGE-Sperren. Was, wenn wir auf eine KEY-Sperre warten?

2) waitresource="KEY: 6:72057594041991168 (ce52f92a058c)" = Database_Id, HOBT_Id (magischer Hash, der mit %%lockres%% entschlüsselt werden kann, falls Sie das wirklich wollen)

Wenn Ihre Abfrage versucht, eine Sperre auf einen Datensatz im Index anzuwenden und selbst blockiert wird, erhalten Sie einen ganz anderen Typ von Adresse.
Zerlegen wir "6:72057594041991168 (ce52f92a058c)" in Teile, erhalten wir:

  • database_id = 6
  • hobt_id = 72057594041991168
  • magischer Hash = (ce52f92a058c)

2.1) Entschlüsseln der database_id

Es funktioniert genau wie das Beispiel oben! Wir finden den DB-Namen mit einer Abfrage:

SELECT 
    name 
FROM sys.databases 
WHERE database_id=6;
GO

In meinem Fall ist es immer noch dasselbe DB WideWorldImporters.

2.2) Entschlüsseln von hobt_id

Im Kontext der gefundenen DB muss eine Abfrage an sys.partitions mit einem Paar Joins durchgeführt werden, die helfen, die Namen der Tabelle und des Index zu bestimmen…

USE WideWorldImporters;
GO
SELECT 
    sc.name as schema_name, 
    so.name as object_name, 
    si.name as index_name
FROM sys.partitions AS p
JOIN sys.objects as so on 
    p.object_id=so.object_id
JOIN sys.indexes as si on 
    p.index_id=si.index_id and 
    p.object_id=si.object_id
JOIN sys.schemas AS sc on 
    so.schema_id=sc.schema_id
WHERE hobt_id = 72057594041991168;
GO

Er sagt mir, dass die Abfrage auf die Sperre von Application.Countries gewartet hat, wobei der Index PK_Application_Countries verwendet wird.

2.3) Jetzt ein wenig Magie %%lockres%% — wenn Sie herausfinden möchten, welcher Datensatz gesperrt war

Wenn ich wirklich wissen möchte, auf welcher Zeile die Sperre benötigt wurde, kann ich dies mit einer Abfrage auf die Tabelle selbst herausfinden. Wir können die nicht dokumentierte Funktion %%lockres%% verwenden, um den Datensatz zu finden, der mit dem magischen Hash übereinstimmt.
Beachten Sie, dass diese Abfrage die gesamte Tabelle durchsuchen wird, und bei großen Tabellen kann das ziemlich unangenehm sein:

SELECT
    *
FROM Application.Countries (NOLOCK)
WHERE %%lockres%% = '(ce52f92a058c)';
GO

Ich habe NOLOCK hinzugefügt (auf den Rat von Klaus Aschenbrenner auf Twitter) weil Sperren problematisch werden können. Wir möchten einfach nur sehen, was dort jetzt ist, und nicht, was dort war, als die Transaktion begann – ich denke nicht, dass uns die Konsistenz der Daten wichtig ist.
Voilà, der Datensatz um den wir gekämpft haben!
Entschlüsselung von Key und Page WaitResource in Deadlocks und Sperren

Danksagungen und weiterführende Literatur

Ich erinnere mich nicht, wer viele dieser Dinge zuerst beschrieben hat, aber hier sind zwei Posts über die am wenigsten dokumentierten Techniken, die Ihnen gefallen könnten:

Quelle: habr.com

60GB SSD 8Gb DDR4