Ontsyfer sleutel en Page WaitResource in dooiepunte en slotte

As jy die geblokkeerde prosesverslag gebruik of die dooiepuntgrafieke wat van tyd tot tyd deur SQL Server verskaf word versamel, sal jy dinge soos hierdie teëkom:

waitresource="BLADSY: 6:3:70133"

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

Soms sal daar meer inligting in daardie reuse-XML wees wat jy bestudeer (dooiepuntgrafieke bevat 'n lys hulpbronne wat jou help om die voorwerp- en indeksname uit te vind), maar nie altyd nie.

Hierdie teks sal jou help om hulle te ontsyfer.

Al die inligting wat hier is, is op verskeie plekke op die internet, dit is net baie versprei! Ek wil alles bymekaar sit - van DBCC PAGE tot hobt_id en tot die ongedokumenteerde %%physloc%% en %%lockres%% funksies.

Kom ons praat eers oor wagte op PAGE-slotte, en dan gaan ons aan na SLEUTEL-slotte.

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

As jou navraag op 'n PAGE-slot wag, sal SQL Server vir jou die adres van daardie bladsy gee.

As ons "PAGE: 6:3:70133" afbreek, kry ons:

  • databasis_id = 6
  • data_lêer_id = 3
  • bladsynommer = 70133

1.1) Dekripteer databasis_id

Kom ons vind die databasisnaam deur die navraag te gebruik:

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

Dit is publiek DB WideWorldImporters op my SQL Server.

1.2) Soek die naam van die datalêer - as jy belangstel

Ons gaan data_file_id in die volgende stap gebruik om die tabelnaam te vind. Jy kan eenvoudig oorslaan na die volgende stap, maar as jy belangstel in die lêernaam, kan jy dit vind deur 'n navraag in die konteks van die gevind databasis uit te voer, deur data_file_id in hierdie navraag te vervang:

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

In die WideWorldImporters-databasis is dit 'n lêer genaamd WWI_UserData en ek het dit herstel na C:MSSQLDATAWideWorldImporters_UserData.ndf. (Oeps, jy het my gevang dat ek lêers op die stelselskyf sit! Nee! Dit was ongemaklik).

1.3) Kry die voorwerp naam van DBCC PAGE

Nou weet ons dat bladsy #70133 in datalêer 3 aan die WorldWideImporters-databasis behoort. Ons kan na die inhoud van hierdie bladsy kyk deur die ongedokumenteerde DBCC BLADSY en spoorvlag 3604 te gebruik.
Let wel: Ek verkies om DBCC PAGE te gebruik op 'n herstelde kopie vanaf 'n rugsteun iewers op 'n ander bediener, want dit is 'n ongedokumenteerde ding. In sommige gevalle het sy kan daartoe lei dat 'n stortingsterrein geskep word (ongeveer. vertaler - die skakel lei ongelukkig nêrens nie, maar te oordeel aan die url, praat ons van gefiltreerde indekse).

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

Deur deur die resultate te blaai, kan jy object_id en index_id vind.
Ontsyfer sleutel en Page WaitResource in dooiepunte en slotte
Amper klaar! Nou kan jy die tabel- en indeksname vind deur die navraag te gebruik:

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

En nou sien ons dat die slotwag op die PK_Sales_OrderLines-indeks van die Sales.OrderLines-tabel was.

Let wel: In SQL Server 2014 en later kan die objeknaam ook gevind word deur die ongedokumenteerde DMO sys.dm_db_database_page_allocations te gebruik. Maar jy moet elke bladsy in die databasis navraag doen, wat nie baie cool lyk vir groot databasisse nie, so ek het DBCC PAGE gebruik.

1.4) Is dit moontlik om die data te sien op die bladsy wat geblokkeer is?

Wel ja. Maar ... is jy seker dat jy dit regtig nodig het?
Dit is stadig, selfs op klein tafeltjies. Maar dit is nogal cool, so aangesien jy tot hier gelees het... kom ons praat oor %%physloc%%!

%%physloc%% is 'n ongedokumenteerde stuk magie wat 'n fisiese identifiseerder vir elke inskrywing terugstuur. jy kan gebruik %%physloc%% saam met sys.fn_PhysLocFormatter in SQL Server 2008 en hoër.

Noudat ons weet dat ons die bladsy in Sales.OrderLines wou sluit, kan ons kyk na al die data in hierdie tabel, wat in datalêer #3 op bladsy #70133 gestoor word, deur hierdie navraag te gebruik:

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

Soos ek gesê het, dit is stadig, selfs op klein tafeltjies. Ek het NOLOCK by die versoek gevoeg, want ons het steeds geen waarborg dat die data waarna ons wil kyk presies dieselfde is as wat dit was toe die slot opgespoor is nie – ons kan dus veilig vuil leeswerk doen.
Maar hoera, die navraag gee vir my dieselfde 25 rye terug waarvoor ons navraag baklei het
Ontsyfer sleutel en Page WaitResource in dooiepunte en slotte
Genoeg oor PAGE-slotte. Wat as ons wag vir 'n SLEUTEL-slot?

2) waitresource=“SLEUTEL: 6:72057594041991168 (ce52f92a058c)” = Database_Id, HOBT_Id (magiese hash wat gedekripteer kan word met %%lockres%% as jy dit regtig wil hê)

As jou navraag probeer om 'n rekord in die indeks te sluit en self gesluit word, eindig jy met 'n heeltemal ander tipe adres.
Deur “6:72057594041991168 (ce52f92a058c)” in dele te breek, kry ons:

  • databasis_id = 6
  • hobt_id = 72057594041991168
  • magiese hash = (ce52f92a058c)

2.1) Dekripteer databasis_id

Dit werk presies dieselfde as die voorbeeld hierbo! Vind die databasisnaam deur die navraag te gebruik:

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

In my geval is dit steeds dieselfde DB WideWorldImporters.

2.2) Dekripteer hobt_id

In die konteks van die databasis wat gevind is, moet jy 'n navraag na sys.partitions uitvoer met 'n paar verbindings wat sal help om die name van die tabel en indeks te bepaal...

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

Dit sê vir my dat die versoek op die Application.Countries-slot gewag het deur die PK_Application_Countries-indeks te gebruik.

2.3) Nou 'n bietjie magie %%lockres%% - as jy wil uitvind watter inskrywing gesluit is

As ek regtig wil weet op watter ry die slot was, kan ek uitvind deur die tabel self te bevraagteken. Ons kan die ongedokumenteerde %%lockres%%-funksie gebruik om 'n inskrywing te vind wat by die magiese hash pas.
Neem asseblief kennis dat hierdie navraag die hele tabel sal skandeer, en op groot tafels sal dit dalk glad nie pret wees nie:

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

Ek het NOLOCK bygevoeg (op advies van Klaus Aschenbrenner op Twitter) omdat blokkasies ’n probleem kan word. Ons wil net kyk na wat nou daar is, en nie wat daar was toe die transaksie begin het nie - ek dink nie dat datakonsekwentheid vir ons belangrik is nie.
Voila, die rekord waarvoor ons baklei het!
Ontsyfer sleutel en Page WaitResource in dooiepunte en slotte

Dankbetuigings en verdere leeswerk

Ek kan nie onthou wie die eerste keer baie van hierdie dinge beskryf het nie, maar hier is twee plasings oor die mins gedokumenteerde dinge waarvan jy dalk sal hou:

Bron: will.com

Voeg 'n opmerking