Dešifreerige võti ja lehe ooteressurss ummikseisudes ja lukkudes

Kui kasutate blokeeritud protsessi aruannet või kogute perioodiliselt SQL Serveri pakutavaid ummikseisu graafikuid, kohtate selliseid asju:

waitresource="LEHT: 6:3:70133"

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

Mõnikord on selles hiiglaslikus XML-is, mida uurite, rohkem teavet (ummikseisu graafikud sisaldavad ressursside loendit, mis aitab teil objekti ja indeksi nimesid välja selgitada), kuid mitte alati.

See tekst aitab teil neid lahti mõtestada.

Kogu siin olev teave on Internetis erinevates kohtades, see on lihtsalt väga levinud! Ma tahan selle kõik kokku panna, alates DBCC PAGE-st kuni hobt_id-ni kuni dokumenteerimata funktsioonideni %%physloc%% ja %%lockres%%.

Kõigepealt räägime PAGE lukkude ootamisest ja seejärel liigume KEY lukkude juurde.

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

Kui teie taotlus ootab PAGE lukus, annab SQL Server teile selle lehe aadressi.

Jaotades "LEHT: 6:3:70133" saame:

  • andmebaasi_id = 6
  • andmefaili_id = 3
  • lehe_number = 70133

1.1) Dekrüpteeri andmebaasi_id

Leidke andmebaasi nimi päringu abil:

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

See on avalik DB WideWorldImporters minu SQL serveris.

1.2) Andmefaili nime otsimine - kui olete huvitatud

Järgmises etapis kasutame tabeli nime leidmiseks faili data_file_id. Võite lihtsalt järgmise sammu juurde liikuda, kuid kui olete failinimest huvitatud, saate selle leida, käivitades leitud andmebaasi kontekstis päringu, asendades selle päringuga data_file_id:

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

WideWorldImportersi andmebaasis on see fail nimega WWI_UserData ja ma lasen selle taastada failiks C:MSSQLDATAWideWorldImporters_UserData.ndf. (Oih, sa tabasid mind süsteemikettale faile panemast! Ei! See on piinlik).

1.3) Hankige objekti nimi lehelt DBCC PAGE

Nüüd teame, et andmefaili 70133 leht #3 kuulub WorldWideImporters andmebaasi. Selle lehe sisu saame vaadata dokumenteerimata DBCC PAGE ja jälgimislipu 3604 abil.
Märkus. Eelistan kasutada DBCC PAGE'i kuskil teises serveris taastatud koopial, kuna see on dokumenteerimata kraam. Mõnel juhul ta võib põhjustada prügimäge (u. tõlkija - link kahjuks ei vii kuhugi, kuid URL-i järgi otsustades räägime filtreeritud indeksitest).

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

Tulemustele kerides leiate objekti_id ja indeksi_id.
Dešifreerige võti ja lehe ooteressurss ummikseisudes ja lukkudes
Peaaegu valmis! Nüüd leiate päringuga tabelite ja indeksinimed:

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

Ja siin näeme, et lukustuse ooteaeg oli Sales.OrderLines tabeli PK_Sales_OrderLines indeksis.

Märkus.: SQL Server 2014 ja uuemates versioonides võib objekti nime leida ka dokumenteerimata DMO sys.dm_db_database_page_allocations abil. Kuid andmebaasis tuleb päringuid teha igalt lehelt, mis ei tundu suurte andmebaaside jaoks eriti lahe, seega kasutasin DBCC PAGE-d.

1.4) Kas blokeeritud lehel on võimalik andmeid näha?

Nuuu, jah. Aga… oled sa kindel, et vajad seda tõesti?
See on aeglane isegi väikestel laudadel. Aga see on omamoodi lahe, nii et kuna olete nii kaugele lugenud, siis räägime %%physloc%%st!

%%physloc%% on dokumentideta maagia, mis tagastab iga kirje füüsilise ID. sa võid kasutada %%physloc%% koos failiga sys.fn_PhysLocFormatter SQL Server 2008 ja uuemates versioonides.

Nüüd, kui teame, et soovisime lehe Sales.OrderLinesis blokeerida, saame vaadata kõiki selle tabelis olevaid andmeid, mis on salvestatud andmefaili #3 leheküljel #70133, järgmise päringuga:

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

Nagu ma ütlesin, on see aeglane isegi väikestel laudadel. Lisasin päringule NOLOCKi, kuna meil pole endiselt garantiid, et andmed, mida tahame vaadata, on täpselt samad, mis luku avastamise ajal olid – nii saame turvaliselt teha määrdunud lugemisi.
Aga, hurraa, päring annab mulle täpselt need 25 rida, mille eest meie päring võitles.
Dešifreerige võti ja lehe ooteressurss ummikseisudes ja lukkudes
Aitab PAGE lukkudest. Mis siis, kui ootame VÕTI lukku?

2) waitresource="KEY: 6:72057594041991168 (ce52f92a058c)" = Database_Id, HOBT_Id (maagiline räsi, mida saab dekrüpteerida funktsiooniga %%lockres%%, kui väga soovite)

Kui teie päring üritab indeksi kirjet lukustada ja lukustub iseenesest, saate täiesti erinevat tüüpi aadressi.
Jagades "6:72057594041991168 (ce52f92a058c)" osadeks, saame:

  • andmebaasi_id = 6
  • hobt_id = 72057594041991168
  • maagiline räsi = (ce52f92a058c)

2.1) Dekrüpteeri andmebaasi_id

See töötab täpselt samamoodi nagu ülaltoodud näite puhul! Andmebaasi nime leiame päringu abil:

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

Minu puhul on see sama DB WideWorldImporters.

2.2) Dekrüpteerige hobt_id

Leitud andmebaasi kontekstis peate tegema päringu sys.partitions paari ühendusega, mis aitavad määrata tabeli ja indeksi nimesid ...

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

See ütleb mulle, et taotlus ootas rakenduses Application.Countries lukustuses PK_Application_Countries indeksi abil.

2.3) Nüüd natuke %%lockres%% maagiat – kui soovite teada saada, milline kirje lukustati

Kui ma tõesti tahan teada, millisele reale lukku vaja oli, saan selle teada tabeli enda päringu kaudu. Võime kasutada dokumentideta funktsiooni %%lockres%%, et leida kirje, mis vastab maagilisele räsile.
Pange tähele, et see päring skannib kogu tabelit ja suurtes tabelites ei pruugi see olla üldse lõbus:

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

Lisasin NOLOCKi (Klaus Aschenbrenneri nõuandel twitteris), sest lukud võivad olla probleemiks. Tahame lihtsalt vaadata, mis seal praegu on, mitte seda, mis oli seal tehingu alguses – ma ei usu, et andmete järjepidevus on meie jaoks oluline.
Voila, rekord, mille eest võitlesime!
Dešifreerige võti ja lehe ooteressurss ummikseisudes ja lukkudes

Tänuavaldused ja edasine lugemine

Ma ei mäleta, kes neid asju esmakordselt kirjeldas, kuid siin on kaks postitust kõige vähem dokumenteeritud asjade kohta, mis teile meeldida võivad:

Allikas: www.habr.com

Lisa kommentaar