Afklaring af Key og Page WaitResource i deadlocks og lÄsninger

Hvis du bruger blocked process report eller samler deadlock-grafer, der gives af SQL Server, vil du fra tid til anden stÞde pÄ sÄdanne ting:

waitresource=“PAGE: 6:3:70133“

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

Nogle gange vil der vÊre mere information i det enorme XML, som du studerer (deadlock-graferne indeholder en liste over ressourcer, der hjÊlper med at finde navne pÄ objekter og indekser), men ikke altid.

Denne tekst vil hjĂŠlpe dig med at afkode dem.

Alle oplysninger, der her findes, er tilgĂŠngelige online pĂ„ forskellige steder, de er bare meget spredte! Jeg vil samle alt sammen — fra DBCC PAGE til hobt_id samt de u-dokumenterede %%physloc%% og %%lockres%% funktioner.

Lad os fÞrst tale om ventetider pÄ PAGE-lÄse, og derefter gÄr vi videre til KEY-lÄse.

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

Hvis din forespÞrgsel venter pÄ en PAGE-lÄs, vil SQL Server give dig adressen pÄ denne side.

Ved at opdele “PAGE: 6:3:70133” fĂ„r vi:

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

1.1) AfdĂŠkker database_id

Lad os finde navnet pÄ databasen med forespÞrgslen:

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

Dette er den offentlige DB WideWorldImporters pÄ min SQL Server.

1.2) SĂžg efter navnet pĂ„ datafilen — hvis du er interesseret

Vi vil bruge data_file_id i nÊste trin for at finde navnet pÄ tabellen. Du kan bare gÄ til nÊste trin, men hvis du er nysgerrig efter filnavnet, kan du finde det ved at udfÞre en forespÞrgsel i sammenhÊng med den fundne DB, ved at indsÊtte data_file_id i denne forespÞrgsel:

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

I DB WideWorldImporters er dette filen kaldet WWI_UserData, og den er gendannet hos mig i C:MSSQLDATAWideWorldImporters_UserData.ndf. (Ups, du fangede mig med at lÊgge filer pÄ disk med systemet! Nej! Det blev akavet).

1.3) FĂ„ objektets navn fra DBCC PAGE

Nu ved vi, at side #70133 i datafilen 3 tilhĂžrer DB WorldWideImporters. Vi kan se indholdet af denne side ved hjĂŠlp af den u-dokumenterede DBCC PAGE og trace-flaget 3604.
BemĂŠrk: Jeg foretrĂŠkker at bruge DBCC PAGE pĂ„ en gendannet kopi fra en backup et sted pĂ„ en anden server, fordi det er en u-dokumenteret ting. I nogle tilfĂŠlde kan det fĂžre til dannelsen af et dump. (note fra oversĂŠtteren — linket fĂžrer desvĂŠrre ingen steder hen, men ifĂžlge URL'en handler det om filtered-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

Scrollende til resultaterne kan man finde object_id og index_id.
Afklaring af Key og Page WaitResource i deadlocks og lÄsninger
NĂŠsten klar! Nu kan du finde tabel- og indeksnavne med forespĂžrgslen:

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Ä blokeringen var pÄ indekset PK_Sales_OrderLines i tabellen Sales.OrderLines.

BemÊrk: I SQL Server 2014 og nyere kan objektets navn ogsÄ findes ved hjÊlp af den ikke-dokumenterede DMO sys.dm_db_database_page_allocations. Men du skal anmode om hver side i databasen, hvilket ikke ser sÄ smart ud for store databaser, sÄ jeg brugte DBCC PAGE.

1.4) Kan vi se dataene pÄ den side, der var blokeret?

NÄ, ja. Men
 er du sikker pÄ, at du virkelig har brug for det?
Det er langsomt, selv pÄ smÄ tabeller. Men det er lidt sjovt, sÄ da du er nÄet til dette punkt... lad os tale om %%physloc%%!

%%physloc%% er et ikke-dokumenteret stykke magi, der returnerer den fysiske identifikator for hver post. Du kan bruge %%physloc%% sammen med sys.fn_PhysLocFormatter i SQL Server 2008 og nyere.

Nu hvor vi ved, at vi gerne ville lÄse siden i Sales.OrderLines, kan vi se alle data i denne tabel, der er gemt i datafil #3 pÄ side #70133, med denne forespÞrgsel:

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

Som jeg sagde — det er langsomt, selv pĂ„ bittesmĂ„ tabeller. Jeg tilfĂžjede NOLOCK til forespĂžrgslen, fordi vi alligevel ikke har nogen garantier for, at de data, vi vil se pĂ„, er prĂŠcis de samme, som de var pĂ„ det tidspunkt, da blokeringen blev opdaget — sĂ„ vi kan roligt lave beskidte lĂŠsninger.
Men hurra, forespĂžrgslen returnerer de 25 rĂŠkker, som vores forespĂžrgsel kĂŠmpede for.
Afklaring af Key og Page WaitResource i deadlocks og lÄsninger
Lad os glemme PAGE-blokeringer. Hvad nu hvis vi venter pÄ KEY-blokering?

2) waitresource=“KEY: 6:72057594041991168 (ce52f92a058c)” = Database_Id, HOBT_Id (et magisk hash, der kan afkodes med %%lockres%%, hvis du virkelig vil)

Hvis din forespÞrgsel forsÞger at lÄse en post i indekset og bliver blokeret selv, fÄr du en helt anden type adresse.
Ved at opdele “6:72057594041991168 (ce52f92a058c)” i dele, fĂ„r vi:

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

2.1) Vi afkoder database_id

Det fungerer ligesom det foregÄende eksempel! Vi finder databasens navn med en forespÞrgsel:

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

I mit tilfĂŠlde er det stadig den samme DB WideWorldImporters.

2.2) Afkode hobt_id

I konteksten af den fundne database skal der udfÞres en forespÞrgsel til sys.partitions med et par join, som hjÊlper med at bestemme navne pÄ tabellen og indekset


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 fortÊller mig, at forespÞrgslen ventede pÄ en lÄs af Application.Countries ved at bruge indekset PK_Application_Countries.

2.3) Nu lidt magi %%lockres%% — hvis du vil finde ud af, hvilken post der var lĂ„st

Hvis jeg virkelig vil finde ud af, hvilken rÊkke lÄsen var nÞdvendig for, kan jeg finde det ved at forespÞrge tabellen selv. Vi kan bruge den uofficielle funktion %%lockres%% til at finde en post, der matcher den magiske hash.
VÊr opmÊrksom pÄ, at denne forespÞrgsel vil scanne hele tabellen, og pÄ store tabeller kan det blive ret besvÊrligt:

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

Jeg tilfĂžjede NOLOCK (efter rĂ„d fra Klaus Aschenbrenner pĂ„ Twitter) fordi lĂ„se kan blive et problem. Vi vil blot se, hvad der er der nu, og ikke hvad der var der, da transaktionen begyndte — jeg tror ikke, at dataintegritet er vigtig for os.
VoilĂ , posten vi kĂŠmpede om!
Afklaring af Key og Page WaitResource i deadlocks og lÄsninger

Tak og videre lĂŠsning

Jeg kan ikke huske, hvem der fÞrst beskrev mange af disse ting, men her er to indlÊg om de mest lidt dokumenterede funktioner, som du mÄske vil finde interessante:

Kilde: habr.com

KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster