Dechiffrer nøkkel og Page WaitResource i vranglåser og låser

Hvis du bruker den blokkerte prosessrapporten eller samler inn deadlock-grafene som leveres av SQL Server med jevne mellomrom, vil du støte på ting som dette:

waitresource="PAGE: 6:3:70133"

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

Noen ganger vil det være mer informasjon i den gigantiske XML-en du studerer (deadlock-grafer inneholder en liste over ressurser som hjelper deg å finne ut navnene på objektet og indeksen), men ikke alltid.

Denne teksten vil hjelpe deg med å tyde dem.

All informasjonen som ligger her ligger på Internett forskjellige steder, den er rett og slett veldig distribuert! Jeg vil sette alt sammen, fra DBCC PAGE til hobt_id til de udokumenterte funksjonene %%physloc%% og %%lockres%%.

La oss først snakke om ventetider på PAGE-låser, og deretter gå videre til KEY-låser.

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

Hvis forespørselen din venter på en PAGE-lås, vil SQL Server gi deg adressen til den siden.

Ved å bryte ned "PAGE: 6:3:70133" får vi:

  • database_id = 6
  • data_fil_id = 3
  • sidenummer = 70133

1.1) Dekrypter database_id

Finn navnet på databasen ved å bruke spørringen:

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

Det er offentlig DB WideWorldImporters på min SQL Server.

1.2) Leter etter navnet på datafilen - hvis du er interessert

Vi skal bruke data_file_id i neste trinn for å finne tabellnavnet. Du kan bare hoppe til neste trinn, men hvis du er interessert i filnavnet, kan du finne det ved å kjøre en spørring i konteksten til databasen som er funnet, og erstatte data_file_id i denne spørringen:

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

I WideWorldImporters-databasen er dette en fil som heter WWI_UserData, og jeg har den gjenopprettet til C:MSSQLDATAWideWorldImporters_UserData.ndf. (Beklager, du tok meg i å legge filer på systemstasjonen! Nei! Det er pinlig).

1.3) Hent objektnavn fra DBCC PAGE

Vi vet nå at side #70133 i datafil 3 tilhører WorldWideImporters-databasen. Vi kan se på innholdet på denne siden ved å bruke den udokumenterte DBCC PAGE og sporingsflagget 3604.
Merk: Jeg foretrekker å bruke DBCC PAGE på en gjenopprettet kopi et sted på en annen server, fordi det er udokumenterte ting. I noen tilfeller har hun kan resultere i en dump (ca. oversetter - lenken fører dessverre ingen steder, men etter nettadressen å dømme snakker vi om filtrerte indekser).

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

Ved å bla til resultatene kan du finne objekt-id og indeks-id.
Dechiffrer nøkkel og Page WaitResource i vranglåser og låser
Nesten ferdig! Nå kan du finne tabell- og indeksnavnene med en spørring:

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

Og her ser vi at ventetiden på låsen var på PK_Sales_OrderLines-indeksen til Sales.OrderLines-tabellen.

Merk: I SQL Server 2014 og nyere kan objektnavnet også finnes ved å bruke den udokumenterte DMO-en sys.dm_db_database_page_allocations. Men du må spørre hver side i databasen, noe som ikke ser veldig kult ut for store databaser, så jeg brukte DBCC PAGE.

1.4) Er det mulig å se dataene på siden som ble blokkert?

Nuuu, ja. Men... er du sikker på at du virkelig trenger det?
Det er tregt selv på små bord. Men det er litt kult, så siden du har lest så langt...la oss snakke om %%physloc%%!

%%physloc%% er et udokumentert stykke magi som returnerer en fysisk ID for hver oppføring. du kan bruke %%physloc%% sammen med sys.fn_PhysLocFormatter i SQL Server 2008 og nyere.

Nå som vi vet at vi ønsket å blokkere siden i Sales.OrderLines, kan vi se på alle dataene i denne tabellen, som er lagret i datafil #3 på side #70133, med følgende spørring:

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

Som jeg sa, det er tregt selv på bittesmå bord. Jeg la til NOLOCK i forespørselen fordi vi fortsatt ikke har noen garantier for at dataene vi ønsker å se på er nøyaktig de samme som de var da låsen ble oppdaget – så vi kan trygt gjøre skitne avlesninger.
Men, hurra, spørringen returnerer meg de 25 radene som søket vårt kjempet for.
Dechiffrer nøkkel og Page WaitResource i vranglåser og låser
Nok om PAGE-låser. Hva om vi venter på en NØKKELlås?

2) waitresource="KEY: 6:72057594041991168 (ce52f92a058c)" = Database_Id, HOBT_Id (magisk hash som kan dekrypteres med %%lockres%% hvis du virkelig vil)

Hvis søket ditt prøver å låse en indeksoppføring og blir låst av seg selv, får du en helt annen type adresse.
Ved å dele "6:72057594041991168 (ce52f92a058c)" i deler, får vi:

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

2.1) Dekrypter database_id

Det fungerer akkurat det samme som med eksemplet ovenfor! Finn databasenavnet ved å bruke spørringen:

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

I mitt tilfelle er det det samme DB WideWorldImporters.

2.2) Dekrypter hobt_id

I sammenheng med databasen som ble funnet, må du spørre etter sys.partitions med et par sammenføyninger som vil hjelpe med å bestemme navnene på tabellen og indeksen ...

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

Den forteller meg at forespørselen ventet på Application.Countries-låsen ved å bruke PK_Application_Countries-indeksen.

2.3) Nå for litt %%lockres%% magi - hvis du vil finne ut hvilken oppføring som ble låst

Hvis jeg virkelig vil vite hvilken rad låsen var nødvendig, kan jeg finne ut av det ved å spørre i selve tabellen. Vi kan bruke den udokumenterte %%lockres%%-funksjonen for å finne en oppføring som samsvarer med den magiske hashen.
Merk at denne spørringen vil skanne hele tabellen, og på store tabeller er dette kanskje ikke morsomt i det hele tatt:

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

Jeg la til NOLOCK (etter råd fra Klaus Aschenbrenner på twitter) fordi låser kan være et problem. Vi vil bare se på hva som er der nå, og ikke hva som var der da transaksjonen startet - jeg tror ikke at datakonsistens er viktig for oss.
Voila, rekorden vi kjempet for!
Dechiffrer nøkkel og Page WaitResource i vranglåser og låser

Takk og videre lesning

Jeg husker ikke hvem som først beskrev mange av disse tingene, men her er to innlegg om de minst dokumenterte tingene du kanskje liker:

Kilde: www.habr.com

Legg til en kommentar