Kui kasutate blokeeritud protsesside aruannet (blocked process report) vĂ”i kogute SQL Serveri poolt pakutavaid deadlock graafe perioodiliselt, siis vĂ”ite aeg-ajalt kokku puutuda jĂ€rgmist tĂŒĂŒpi asjadega:
waitresource="PAGE: 6:3:70133"
waitresource="KEY: 6:72057594041991168 (ce52f92a058c)"
MÔnikord on selles hiiglaslikus XML-is, mida te uurite, rohkem teavet (deadlock graafid sisaldavad ressursside loetelu, mis aitab tuvastada objekti ja indeksi nimed), aga see ei ole alati nii.
See tekst aitab teil neid deĆĄifreerida.
Kogu teave, mis siin on, on internetis eri kohtades, lihtsalt vĂ€ga hajutatuna! Ma tahan kĂ”ik kokku koguda â alates DBCC PAGE'ist kuni hobt_id ja dokumenteerimata %%physloc%% ja %%lockres%% funktsioonideni.
Esmalt rÀÀgime PAGE-blokeeringute ootamisest, seejÀrel liigume KEY-blokeeringute juurde.
1) waitresource="PAGE: 6:3:70133" =Â Database_Id: FileId: PageNumber
Kui teie pÀring ootab PAGE-blokeeringule, annab SQL Server teile selle lehe aadressi.
LÀbi «PAGE: 6:3:70133» saame:
- database_id = 6
- data_file_id = 3
- page_number = 70133
1.1) DeĆĄifreerime database_id
Otsime andmebaasi nime pÀringu abil:
SELECT
name
FROM sys.databases
WHERE database_id=6;
GOSee on avalik minu SQL Serveris.
1.2) Otsime andmefaili nime â kui teid huvitab
Kavandame kasutada data_file_id jÀrgmisel sammul, et leida tabeli nimi. Te vÔite lihtsalt minna jÀrgmisele sammale, aga kui teid huvitab faili nimi, vÔite selle leida, tehes pÀringu leitud andmebaasi kontekstis, asendades data_file_id selles pÀringus:
USE WideWorldImporters;
GO
SELECT
name,
physical_name
FROM sys.database_files
WHERE file_id = 3;
GOAndmebaasis WideWorldImporters on see fail nimega WWI_UserData ja see on taastatud minu C:MSSQLDATAWideWorldImporters_UserData.ndf. (Ups, tabasite mind failide ketasĂŒsteemi panemise pealt! Ei! NĂŒĂŒd on kohatu!).
1.3) Saame objekti nime DBCC PAGE'ist
NĂŒĂŒd teame, et leht #70133 andmefailis 3 kuulub andmebaasile WorldWideImporters. Saame vaadata selle lehe sisu dokumendivĂ€lise DBCC PAGE'i ja jĂ€lgimislipu 3604 abil.
MĂ€rkus: ma eelistan kasutada DBCC PAGE'i taastatud varukoopia koopia peal kuskil teisel serveril, sest see on dokumendivĂ€line asi. MĂ”nes olukorras vĂ”ib see (tĂ”lki mĂ€rkus â link viib kahjuks tĂŒhjast kohta, aga URL-i pĂ”hjal tĂ”enĂ€oliselt 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 Tulemusi sirvides vÔib leida object_id ja index_id.

Peaaegu valmis! NĂŒĂŒd saab tabeli ja indeksi nimed leida pĂ€ringu abil:
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;
GOJa nĂŒĂŒd nĂ€eme, et ooteaeg lukustamisel oli indeksi PK_Sales_OrderLines tabelis Sales.OrderLines.
MĂ€rkus: SQL Server 2014 ja uuemates saab objekti nime leida ka dokumenteerimata DMO sys.dm_db_database_page_allocations abil. Kuid peate kĂŒsima iga lehe kohta andmebaasis, mis ei tundu vĂ€ga hea suurte andmebaaside puhul, seega kasutasin DBCC PAGE'i.
1.4) Kas on vÔimalik nÀha andmeid lukustatud lehel?
Hmm, jah. Aga... kas olete kindel, et see on teile tÔesti vajalik?
See on aeglane isegi vÀikestes tabelites. Kuid see on kuidagi lahe, seega, kuna olete siiani lugenud... rÀÀgime %%physloc%%-ist!
%%physloc%% on dokumenteerimata tĂŒkk maagia, mis tagastab fĂŒĂŒsilise identifikaatori iga kirje jaoks. Saate kasutada .
NĂŒĂŒd, kui me teame, et tahtsime lukustada lehte tabelis Sales.OrderLines, saame vaadata kĂ”iki selle tabeli andmeid, mis on salvestatud andmefailis #3 lehel #70133, kasutades sellist pĂ€ringut:
Use WideWorldImporters;
GO
SELECT
sys.fn_PhysLocFormatter (%%physloc%%),
*
FROM Sales.OrderLines (NOLOCK)
WHERE sys.fn_PhysLocFormatter (%%physloc%%) like '(3:70133%'
GONagu ma ĂŒtlesin â see on aeglane isegi tillukestes tabelites. Lisasin pĂ€ringule NOLOCK, kuna meil pole ikkagi mingeid garantiisid, et andmed, mida soovime vaadata, on tĂ€pselt need, mis olid lukustamise avastamise hetkel â nii et saame rahulikult teha musti lugemisi.
Aga, jee, pÀring tagastab mulle need 25 rida, mille nimel meie pÀring vÔitles

JÀta PAGE-lukustused kÔrvale. Mis siis, kui ootame KEY-lukustust?
2) waitresource=âKEY: 6:72057594041991168 (ce52f92a058c)â = Database_Id, HOBT_Id (maagiline hash, mille saab dekrĂŒpteerida %%lockres%%-iga, kui soovite seda tĂ”esti teha)
Kui teie pĂ€ring ĂŒritab lukustada kirjet indeksis ja jÀÀb ise lukku, saad accessun teistsuguse aadressi tĂŒĂŒbi.
TĂŒkeldades â6:72057594041991168 (ce52f92a058c)â saame:
- database_id = 6
- hobt_id = 72057594041991168
- maagiline hash = (ce52f92a058c)
2.1) DekrĂŒpteerime database_id
See töötab tÀpselt samamoodi nagu eespool toodud nÀites! Leiame andmebaasi nime pÀringu abil:
SELECT
name
FROM sys.databases
WHERE database_id=6;
GOMinu puhul on see ikka sama .
2.2) Dekodeerime hobt_id
Kontekstis leitud andmebaasis tuleb teha pÀring sys.partitions tabelisse, koos paari join'iga, mis aitavad tuvastada tabeli ja indeksi nimed...
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;
GOSee ĂŒtleb mulle, et pĂ€ring ootas blokkeeringut Application.Countries, kasutades indeksi PK_Application_Countries.
2.3) NĂŒĂŒd vĂ€ike maagia %%lockres%% â kui soovite teada, milline rekord oli blokeeritud
Kui ma tÔesti tahan teada, millisel real blokkeerimine toimus, vÔin seda vÀlja selgitada pÀringuga iseenda tabeli vastu. Saame kasutada dokumenteerimata funktsiooni %%lockres%%, et leida rekord, mis vastab maagilisele hash'ile.
Pidage meeles, et see pÀring skaneerib kogu tabelit, ja suurte tabelite puhul ei pruugi see olla just kÔige toredam:
SELECT
*
FROM Application.Countries (NOLOCK)
WHERE %%lockres%% = '(ce52f92a058c)';
GO Lisasin NOLOCK () kuna lukud vĂ”ivad probleemiks osutuda. Soovime lihtsalt vaadata, mis seal hetkel on, mitte mis seal oli, kui tehing algas â ei arva, et andmete jĂ€rjepidevus on meile oluline.
Voilà , rekord, mille nimel me vÔitlesime!

TĂ€nud ja edasi lugemine
Ei mÀleta, kes esimesena paljusid neist asjadest kirjeldas, aga siin on kaks postitust kÔige vÀhem dokumenteeritud asjadest, mis vÔivad teile meeldida:
- Paul Randi postitus (kuidas me oma andmed esimeses nÀites leidisime)
- KĂŒsimus StackOverflow's (kuidas me andmed teises nĂ€ites leidsime). Ăks vastus viib postituseni .
Allikas: habr.com
