Iššifruokite raktą ir puslapio laukimo išteklius aklavietėse ir užraktuose

Jei naudosite užblokuoto proceso ataskaitą arba periodiškai renkate aklavietės diagramas, kurias pateikia SQL Server, susidursite su tokiais dalykais:

waitresource=“PUSLAPIS: 6:3:70133“

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

Kartais tame milžiniškame XML, kurį studijuojate, bus daugiau informacijos (aklavietės diagramose yra išteklių sąrašas, padedantis sužinoti objektų ir indeksų pavadinimus), bet ne visada.

Šis tekstas padės jums juos iššifruoti.

Visa informacija, kuri čia yra, yra internete įvairiose vietose, tiesiog labai išplatinta! Noriu sujungti viską – nuo ​​DBCC PAGE iki hobt_id ir iki nedokumentuotų %%physloc%% ir %%lockres%% funkcijų.

Pirmiausia pakalbėkime apie laukimą PAGE užraktuose, o tada pereisime prie KEY užraktų.

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

Jei jūsų užklausa laukia PAGE užrakto, SQL serveris suteiks jums to puslapio adresą.

Išskaidę „PAGE: 6:3:70133“ gauname:

  • duomenų bazės_id = 6
  • duomenų_failo_id = 3
  • puslapio_numeris = 70133

1.1) Iššifruoti duomenų bazės_id

Raskime duomenų bazės pavadinimą naudodami užklausą:

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

Tai vieša DB WideWorldImporters mano SQL serveryje.

1.2) Ieškote duomenų failo pavadinimo – jei domina

Kitame žingsnyje naudosime data_file_id, kad surastume lentelės pavadinimą. Galite tiesiog pereiti prie kito veiksmo, bet jei jus domina failo pavadinimas, galite jį rasti paleisdami užklausą rastos duomenų bazės kontekste, šioje užklausoje pakeisdami data_file_id:

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

„WideWorldImporters“ duomenų bazėje tai yra failas pavadinimu WWI_UserData ir aš jį atkūriau į C:MSSQLDATAWideWorldImporters_UserData.ndf. (Oi, pagavote mane dedant failus į sistemos diską! Ne! Tai buvo nepatogu).

1.3) Gaukite objekto pavadinimą iš DBCC PAGE

Dabar žinome, kad puslapis #70133 3 duomenų faile priklauso WorldWideImporters duomenų bazei. Šio puslapio turinį galime peržiūrėti naudodami nedokumentuotą DBCC PAGE ir sekimo vėliavėlę 3604.
Pastaba: Man labiau patinka naudoti DBCC PAGE atkurtoje kopijoje iš atsarginės kopijos kitame serveryje, nes tai yra nedokumentuotas dalykas. Kai kuriais atvejais ji gali atsirasti sąvartynas (apytiksliai vertėjas - nuoroda, deja, niekur neveda, bet sprendžiant iš URL, mes kalbame apie filtruotus indeksus).

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

Slinkdami per rezultatus galite rasti objekto_id ir indekso_id.
Iššifruokite raktą ir puslapio laukimo išteklius aklavietėse ir užraktuose
Beveik baigta! Dabar galite rasti lentelių ir indeksų pavadinimus naudodami užklausą:

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

Ir dabar matome, kad užrakto laukimas buvo lentelės Sales.OrderLines indekse PK_Sales_OrderLines.

Pastaba: SQL Server 2014 ir vėlesnėse versijose objekto pavadinimą taip pat galima rasti naudojant nedokumentuotą DMO sys.dm_db_database_page_allocations. Bet jūs turite pateikti užklausą kiekviename duomenų bazės puslapyje, o tai neatrodo labai šaunu didelėms duomenų bazėms, todėl naudojau DBCC PAGE.

1.4) Ar galima matyti duomenis puslapyje, kuris buvo užblokuotas?

Na taip. Bet... ar esi tikras, kad tau to tikrai reikia?
Tai lėta net ant mažų stalų. Bet tai šaunu, todėl kadangi jau perskaitėte iki šiol... pakalbėkime apie %%physloc%%!

%%physloc%% yra nedokumentuota magija, kuri kiekvienam įrašui pateikia fizinį identifikatorių. tu gali naudoti %%physloc%% kartu su sys.fn_PhysLocFormatter SQL Server 2008 ir naujesnėje versijoje.

Dabar, kai žinome, kad norėjome užrakinti puslapį Sales.OrderLines, galime peržiūrėti visus šios lentelės duomenis, kurie yra saugomi duomenų faile Nr. 3 70133 puslapyje, naudodami šią užklausą:

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

Kaip jau sakiau, jis lėtas net ant mažų stalų. Prie užklausos pridėjau NOLOCK, nes vis dar neturime garantijos, kad duomenys, kuriuos norime peržiūrėti, yra lygiai tokie patys, kokie buvo tada, kai buvo aptiktas užraktas, todėl galime saugiai atlikti nešvarius skaitymus.
Bet užklausa man pateikia tas pačias 25 eilutes, dėl kurių kovojo mūsų užklausa
Iššifruokite raktą ir puslapio laukimo išteklius aklavietėse ir užraktuose
Užteks apie PAGE užraktus. Ką daryti, jei laukiame KEY užrakto?

2) waitresource=“KEY: 6:72057594041991168 (ce52f92a058c)” = Database_Id, HOBT_Id (stebuklinga maiša, kurią galima iššifruoti naudojant %%lockres%%, jei tikrai to norite)

Jei jūsų užklausa bando užrakinti įrašą indekse ir užrakinama pati, gausite visiškai kitokio tipo adresą.
Suskaidžius „6:72057594041991168 (ce52f92a058c)“ į dalis, gauname:

  • duomenų bazės_id = 6
  • hobt_id = 72057594041991168
  • magija maiša = (ce52f92a058c)

2.1) Iššifruoti duomenų bazės_id

Tai veikia lygiai taip pat, kaip aukščiau pateiktas pavyzdys! Raskite duomenų bazės pavadinimą naudodami užklausą:

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

Mano atveju vis tiek tas pats DB WideWorldImporters.

2.2) Iššifruoti hobt_id

Rastos duomenų bazės kontekste reikia vykdyti sys.partitions užklausą su jungčių pora, kuri padės nustatyti lentelės ir indekso pavadinimus...

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

Ji man sako, kad užklausa laukė Application.Countries užrakinimo naudojant PK_Application_Countries indeksą.

2.3) Dabar šiek tiek magijos %%lockres%% – jei norite sužinoti, kuris įrašas buvo užrakintas

Jei tikrai noriu sužinoti, kurioje eilutėje buvo užraktas, tai galiu sužinoti užklausęs pačią lentelę. Galime naudoti nedokumentuotą %%lockres%% funkciją, kad rastume įrašą, atitinkantį magišką maišą.
Atminkite, kad ši užklausa nuskaitys visą lentelę, o didelėse lentelėse tai gali būti visai neįdomu:

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

Aš pridėjau NOLOCK (Klauso Aschenbrennerio patarimu socialiniame tinkle „Twitter“.), nes užsikimšimai gali tapti problema. Tiesiog norime pažvelgti į tai, kas ten yra dabar, o ne į tai, kas buvo, kai prasidėjo sandoris – nemanau, kad duomenų nuoseklumas mums yra svarbus.
Voila, rekordas, dėl kurio kovojome!
Iššifruokite raktą ir puslapio laukimo išteklius aklavietėse ir užraktuose

Padėka ir tolesnis skaitymas

Neprisimenu, kas pirmasis aprašė daugelį šių dalykų, bet čia yra du įrašai apie mažiausiai dokumentuotus dalykus, kurie jums gali patikti:

Šaltinis: www.habr.com

Добавить комментарий