Kui kasutate blokeeritud protsesside aruannet (blocked process report) vÔi kogute SQL Serveri poolt pakutavaid deadlock graafe, kohtate te perioodiliselt jÀrgmisi asju:
waitresource="PAGE: 6:3:70133"
waitresource="KEY: 6:72057594041991168 (ce52f92a058c)"
MÔnikord on selles hiiglaslikus XML-is, mida te uurite, rohkem teavet (deadlock graafides on ressursid, mis aitavad objekte ja indekseid tuvastada), kuid mitte alati.
See tekst aitab teil neid deĆĄifreerida.
Kogu teave, mis siin on, on internetis erinevates kohtades olemas, see on lihtsalt vĂ€ga laiali jaotatud! Ma tahan selle kĂ”ik kokku koguda â alates DBCC PAGE-st kuni hobt_id ja dokumenteerimata %%physloc%% ja %%lockres%% funktsioonideni.
Esiteks rÀÀgime PAGE-blokeeringute ootamisest ja seejÀrel liigume KEY-blokeeringute juurde.
1) waitresource="PAGE: 6:3:70133" = Database_Id: FileId: PageNumber
Kui teie pÀring ootab PAGE-blokeeringut, annab SQL Server teile selle lehe aadressi.
Lahutades "PAGE: 6:3:70133", saame:
- database_id = 6
- data_file_id = 3
- page_number = 70133
1.1) DeĆĄifreerime database_id
Leidke andmebaasi nimi, kasutades pÀringut:
SELECT
name
FROM sys.databases
WHERE database_id=6;
GOSee on avalik minu SQL Serveris.
1.2) Otsime andmefaili nime â kui see huvitab teid
Kavatseme kasutame data_file_id jÀrgmises sammus, et leida tabeli nimi. VÔite lihtsalt edasi liikuda, kuid kui teid huvitab faili nimi, leiate selle, tehes pÀringu leitud andmebaasis, asendades query_sellen data_file_id-ga:
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 jaoks C:MSSQLDATAWideWorldImporters_UserData.ndf. (Ups, sa tabasid mind just sel hetkel, kui ma faile kÔvakettale panin! Ei! Jube piinlik.)
1.3) Saame objekti nime DBCC PAGE-st
NĂŒĂŒd teame, et lehekĂŒlg #70133 andmefailis 3 kuulub andmebaasile WorldWideImporters. Saame selle lehe sisu vaadata dokumenteerimata DBCC PAGE abil ja jĂ€lgimislipiku 3604 abil.
MĂ€rkus: eelistan kasutada DBCC PAGE-d taastatud varukoopia koopia peal, mis asub kuskil teisel serveril, kuna see on dokumenteerimata asi. MĂ”nes olukorras vĂ”ib see (tĂ”lkija mĂ€rkuseks â link viib kahjuks ei kuhugi, kuid URL-i jĂ€rgi nĂ€ib teema olevat filtreeritud indeksite kohta).
/* 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 Kui tulemusi sirvida, vÔib leida object_id ja index_id.

Peaaegu valmis! NĂŒĂŒd saab tabelite ja indeksite nimesid leida pĂ€ringuga:
USE WideWorldImporters;
GO
SELECT
sc.name as schema_nimi,
so.name as objekti_nimi,
si.name as indeks_nimi
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 siin me nÀeme, et ootamine lukustamisel oli indeksi PK_Sales_OrderLines tabelis Sales.OrderLines.
MĂ€rkus: SQL Server 2014 ja uuemates versioonides saab objekti nime leida ka dokumenteerimata DMO sys.dm_db_database_page_allocations abil. Kuid peate kĂŒsima iga lehe DB-s, mis ei tundu suurte andmebaaside jaoks eriti Ă€gedana, seega kasutasin DBCC PAGE.
1.4) Kas on vÔimalik nÀha andmeid lukustatud lehe kohta?
Noh, jah. Aga... kas olete kindel, et see on tÔesti vajalik?
See on aeglane isegi vÀikeste tabelite puhul. Kuid see on kuidagi Àge, nii et kuna olete selle punktini jÔudnud... rÀÀkigem %%physloc%%-st!
%%physloc%% on dokumenteerimata maagia tĂŒkk, mis tagastab iga kirje fĂŒĂŒsilise identifikaatori. Saate kasutada .
NĂŒĂŒd, kui me teame, et soovisime lehe Sales.OrderLines blokeerimist, saame vaadata kĂ”iki andmeid selles tabelis, mis on salvestatud andmefailis #3 lehe #70133 peal, jĂ€rgmise pĂ€ringu abil:
Kasutage WideWorldImporters;
GO
SELECT
sys.fn_PhysLocFormatter (%%physloc%%),
*
FROM Sales.OrderLines (NOLOCK)
WHERE sys.fn_PhysLocFormatter (%%physloc%%) like '(3:70133%'
GONagu ma ĂŒtlesin â see on isegi vĂ€ikestes tabelites aeglane. Lisasin pĂ€ringule NOLOCK, sest meil ei ole ikkagi mingeid garantiisid, et andmed, mida tahame vaadata, on need samad, mis olid hetkel, kui blokeering avastati â seega vĂ”ime rahulikult teha rĂ€paseid lugemisi.
Aga, hurraa, pÀring tagastab mulle need 25 rida, mille nimel meie pÀring vÔitles

Piisavalt PAGE-blokeeringutest. Mis juhtub, kui ootame KEY-blokeeringut?
2) waitresource=âKEY: 6:72057594041991168 (ce52f92a058c)â = Database_Id, HOBT_Id (salajane hash, mille saab dekrĂŒpteerida %%lockres%% abil, kui tĂ”eliselt soovite)
Kui teie pĂ€ring pĂŒĂŒab blokeerida salvestust indeksis ja jÀÀb ise blokeerituks, saate hoopis teistsuguse aadressi.
Lahutades â6:72057594041991168 (ce52f92a058c)â osadeks, saame:
- database_id = 6
- hobt_id = 72057594041991168
- salajane hash = (ce52f92a058c)
2.1) Dekodeerime database_id
See töötab tÀpselt nii nagu eespool oleva nÀite puhul! Otsime andmebaasi nime pÀringu kaudu:
SELECT
name
FROM sys.databases
WHERE database_id=6;
GOMinu puhul on see ikka sama .
2.2) Dekodeerime hobt_id
Leitud andmebaasi kontekstis tuleb teha pÀring sys.partitions tabelisse koos paariga joinidest, 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 blokkeerimist Application.Countries, kasutades indeksi PK_Application_Countries.
2.3) NĂŒĂŒd pisut vĂ”lu %%lockres%% â kui soovite vĂ€lja selgitada, milline kirje oli lukustatud
Kui ma tÔeliselt tahan teada, millisel real lukustus oli vajalik, saan selle vÀlja selgitada pÀringuga tabeli enda peale. Saame kasutada dokumenteerimata funktsiooni %%lockres%%, et leida kirje, mis vastab maagilisele rÀsi.
Pidage meeles, et see pĂ€ring skannib kogu tabelit, ja suurte tabelite korral vĂ”ib see olla ĂŒsna tĂŒlikas:
SELECT
*
FROM Application.Countries (NOLOCK)
WHERE %%lockres%% = '(ce52f92a058c)';
GO Olen lisanud NOLOCK () kuna blokeeringud vĂ”ivad probleemiks muutuda. Me tahame lihtsalt vaadata, mis seal hetkel toimub, mitte seda, mis seal oli, kui tehing algas â ei arva, et andmete jĂ€rjepidevus on meile oluline.
VÔta nÀpust, see on rekord, mille nimel me vÔitlesime!

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