Dekodeerime Key ja Page WaitResource deadlock'ides ja lukustustes.

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;
GO

See on avalik andmebaas WideWorldImporters 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;
GO

Andmebaasis 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 vĂ”ib pĂ”hjustada mĂ€lestuse loomise (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.
Dekodeerime Key ja Page WaitResource deadlock'ides ja lukustustes.
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;
GO

Ja 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 %%physloc%% koos sys.fn_PhysLocFormatteriga SQL Serveris 2008 ja uuemates..

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%'
GO

Nagu 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
Dekodeerime Key ja Page WaitResource deadlock'ides ja lukustustes.
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;
GO

Minu puhul on see ikka sama andmebaas WideWorldImporters.

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;
GO

See ĂŒ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 (Klaus Aschenbrenneri soovitusel Twitteris) 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!
Dekodeerime Key ja Page WaitResource deadlock'ides ja lukustustes.

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:

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster