Dechiffrera nyckel och Page WaitResource i blockerat låsläge och lås

Om du använder den blockerade processrapporten eller samlar in deadlock-graferna som tillhandahålls av SQL Server med jämna mellanrum, kommer du att stöta på saker som detta:

waitresource="SIDA: 6:3:70133"

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

Ibland kommer det att finnas mer information i den gigantiska XML som du studerar (deadlock-grafer innehåller en lista med resurser som hjälper dig att ta reda på namnen på objektet och indexet), men inte alltid.

Den här texten hjälper dig att tyda dem.

All information som finns här finns på Internet på olika ställen, den är helt enkelt väldigt spridd! Jag vill sätta ihop allt, från DBCC PAGE till hobt_id till de odokumenterade funktionerna %%physloc%% och %%lockres%%.

Låt oss först prata om väntetider på PAGE-lås och sedan gå vidare till KEY-lås.

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

Om din begäran väntar på ett PAGE-lås kommer SQL Server att ge dig adressen till den sidan.

Om vi ​​bryter ner "PAGE: 6:3:70133" får vi:

  • database_id = 6
  • data_fil_id = 3
  • sidnummer = 70133

1.1) Dekryptera database_id

Hitta namnet på databasen med hjälp av frågan:

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

Det är offentligt DB WideWorldImporters på min SQL Server.

1.2) Letar efter namnet på datafilen - om du är intresserad

Vi kommer att använda data_file_id i nästa steg för att hitta tabellnamnet. Du kan bara hoppa till nästa steg, men om du är intresserad av filnamnet kan du hitta det genom att köra en fråga i sammanhanget för den hittade databasen och ersätta data_file_id i denna fråga:

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

I WideWorldImporters-databasen är detta en fil som heter WWI_UserData och jag har återställt den till C:MSSQLDATAWideWorldImporters_UserData.ndf. (Hoppsan, du fångade mig när jag lade filer på systemenheten! Nej! Det är pinsamt).

1.3) Hämta objektnamn från DBCC PAGE

Vi vet nu att sida #70133 i datafil 3 tillhör WorldWideImporters databas. Vi kan titta på innehållet på denna sida med den odokumenterade DBCC PAGE och spårningsflagga 3604.
Notera: Jag föredrar att använda DBCC PAGE på en återställd kopia någonstans på en annan server, eftersom det är odokumenterade saker. I vissa fall har hon kan resultera i en dumpning (cirka. översättare - länken leder tyvärr ingenstans, men av webbadressen att döma talar vi om filtrerade index).

/* 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

Genom att scrolla till resultaten kan du hitta objekt-id och index_id.
Dechiffrera nyckel och Page WaitResource i blockerat låsläge och lås
Nästan klar! Nu kan du hitta tabell- och indexnamnen med en fråga:

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

Och här ser vi att väntan på låset var på PK_Sales_OrderLines-indexet i tabellen Sales.OrderLines.

Obs: I SQL Server 2014 och senare kan objektnamnet också hittas med den odokumenterade DMO:n sys.dm_db_database_page_allocations. Men du måste fråga varje sida i databasen, vilket inte ser särskilt coolt ut för stora databaser, så jag använde DBCC PAGE.

1.4) Är det möjligt att se uppgifterna på sidan som blockerades?

Nuuu, ja. Men... är du säker på att du verkligen behöver det?
Det går långsamt även på små bord. Men det är lite coolt, så eftersom du har läst så här långt...låt oss prata om %%physloc%%!

%%physloc%% är ett odokumenterat stycke magi som returnerar ett fysiskt ID för varje post. du kan använda %%physloc%% tillsammans med sys.fn_PhysLocFormatter i SQL Server 2008 och senare.

Nu när vi vet att vi ville blockera sidan i Sales.OrderLines kan vi titta på all data i den här tabellen, som är lagrad i datafil #3 på sida #70133, med följande fråga:

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

Det går som sagt långsamt även på små bord. Jag lade till NOLOCK i förfrågan eftersom vi fortfarande inte har någon garanti för att den data vi vill titta på är exakt densamma som den var när låset upptäcktes - så vi kan säkert göra smutsavläsningar.
Men hurra, frågan returnerar mig just de 25 raderna som vår fråga kämpade för.
Dechiffrera nyckel och Page WaitResource i blockerat låsläge och lås
Nog om PAGE-lås. Vad händer om vi väntar på ett KEY-lås?

2) waitresource="KEY: 6:72057594041991168 (ce52f92a058c)" = Database_Id, HOBT_Id (magisk hash som kan dekrypteras med %%lockres%% om du verkligen vill)

Om din fråga försöker låsa en indexpost och blir låst av sig själv får du en helt annan typ av adress.
Om vi ​​delar upp "6:72057594041991168 (ce52f92a058c)" i delar får vi:

  • database_id = 6
  • hobt_id = 72057594041991168
  • magisk hash = (ce52f92a058c)

2.1) Dekryptera database_id

Det fungerar precis som med exemplet ovan! Vi hittar namnet på databasen med hjälp av frågan:

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

I mitt fall är det samma sak DB WideWorldImporters.

2.2) Dekryptera hobt_id

I samband med den hittade databasen måste du fråga sys.partitions med ett par joins som hjälper till att bestämma namnen på tabellen och index ...

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

Det säger mig att begäran väntade på Application.Countries-låset med hjälp av PK_Application_Countries-indexet.

2.3) Nu till lite %%lockres%% magi - om du vill ta reda på vilken post som var låst

Om jag verkligen vill veta på vilken rad låset behövdes kan jag ta reda på det genom att fråga själva tabellen. Vi kan använda den odokumenterade %%lockres%%-funktionen för att hitta en post som matchar den magiska hashen.
Observera att den här frågan kommer att skanna hela tabellen, och på stora tabeller kanske det inte alls är kul:

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

Jag lade till NOLOCK (på inrådan av Klaus Aschenbrenner på twitter) eftersom lås kan vara ett problem. Vi vill bara titta på vad som finns där nu, och inte vad som fanns där när transaktionen började - jag tror inte att datakonsistens är viktigt för oss.
Voila, rekordet vi kämpade för!
Dechiffrera nyckel och Page WaitResource i blockerat låsläge och lås

Tack och vidare läsning

Jag kommer inte ihåg vem som först beskrev många av dessa saker, men här är två inlägg om de minst dokumenterade sakerna du kanske gillar:

Källa: will.com

Lägg en kommentar