Si vous utilisez le rapport sur les blocages (blocked process report) ou collectez des graphiques de blocage fournis par SQL Server, vous rencontrerez parfois des éléments tels que :
waitresource="PAGE: 6:3:70133"
waitresource="KEY: 6:72057594041991168 (ce52f92a058c)"
Parfois, dans ce gigantesque XML que vous étudiez, il y aura plus d'informations (les graphiques de blocage contiennent une liste de ressources qui aide à identifier les noms des objets et des index), mais ce n'est pas toujours le cas.
Ce texte vous aidera à les décoder.
Toutes les informations présentes ici sont sur Internet à divers endroits, elles sont simplement trÚs dispersées ! Je veux rassembler tout cela - de DBCC PAGE à hobt_id et aux fonctions non documentées %%physloc%% et %%lockres%%.
D'abord, parlons des attentes sur les blocages PAGE, puis passons aux blocages KEY.
1) waitresource="PAGE: 6:3:70133" = Database_Id: FileId: PageNumber
Si votre requĂȘte attend un blocage PAGE, SQL Server vous donnera l'adresse de cette page.
En décomposant «PAGE: 6:3:70133», nous obtenons :
- database_id = 6
- data_file_id = 3
- page_numer = 70133
1.1) Décodons database_id
Trouvons le nom de la base de donnĂ©es avec la requĂȘte :
SELECT
name
FROM sys.databases
WHERE database_id=6;
GOC'est une base de données publique sur mon SQL Server.
1.2) Recherche du nom du fichier de données - si cela vous intéresse
Nous allons utiliser data_file_id Ă l'Ă©tape suivante pour trouver le nom de la table. Vous pouvez simplement passer Ă l'Ă©tape suivante, mais si vous ĂȘtes intĂ©ressĂ© par le nom du fichier, vous pouvez le trouver en exĂ©cutant une requĂȘte dans le contexte de la base de donnĂ©es trouvĂ©e, en substituant data_file_id dans cette requĂȘte :
USE WideWorldImporters;
GO
SELECT
name,
physical_name
FROM sys.database_files
WHERE file_id = 3;
GODans la base de donnĂ©es WideWorldImporters, ce fichier est nommĂ© WWI_UserData et il est restaurĂ© chez moi dans C:MSSQLDATAWideWorldImporters_UserData.ndf. (Oups, vous m'avez pris en train de mettre des fichiers sur un disque systĂšme ! Non ! Ăa a mal tournĂ©).
1.3) Obtenir le nom de l'objet Ă partir de DBCC PAGE
Maintenant, nous savons que la page #70133 dans le fichier de données 3 appartient à la base de données WorldWideImporters. Nous pouvons examiner le contenu de cette page en utilisant DBCC PAGE non documenté et le trace flag 3604.
Remarque : je préfÚre utiliser DBCC PAGE sur une copie récupérée à partir d'une sauvegarde quelque part sur un autre serveur, car c'est une chose non documentée. Dans certains cas, cela peut (Note du traducteur - le lien mÚne malheureusement nulle part, mais d'aprÚs l'url, il s'agit d'index filtrés).
/* 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 En consultant les résultats, on peut trouver object_id et index_id.

Presque prĂȘt ! Vous pouvez maintenant trouver les noms de table et d'index Ă l'aide de la requĂȘte :
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;
GOEt nous pouvons voir que l'attente sur le verrou était sur l'index PK_Sales_OrderLines de la table Sales.OrderLines.
Remarque : dans SQL Server 2014 et version ultĂ©rieure, le nom de l'objet peut Ă©galement ĂȘtre trouvĂ© Ă l'aide de la DMO non documentĂ©e sys.dm_db_database_page_allocations. Mais vous devrez interroger chaque page dans la base de donnĂ©es, ce qui n'est pas trĂšs Ă©lĂ©gant pour les grandes bases de donnĂ©es, c'est pourquoi j'ai utilisĂ© DBCC PAGE.
1.4) Peut-on voir les données à la page qui a été verrouillée ?
Eh bien, oui. Mais⊠ĂȘtes-vous sĂ»rs que câest vraiment ce dont vous avez besoin ?
C'est lent mĂȘme sur de petites tables. Mais c'est plutĂŽt amusant, donc, puisque vous avez lu jusqu'ici⊠parlons de %%physloc%% !
%%physloc%% est un morceau non documenté de magie qui retourne l'identifiant physique pour chaque enregistrement. Vous pouvez utiliser .
Maintenant que nous savons que nous voulions verrouiller la page dans Sales.OrderLines, nous pouvons voir toutes les donnĂ©es dans cette table, qui sont stockĂ©es dans le fichier de donnĂ©es #3 Ă la page #70133, Ă l'aide de cette requĂȘte :
Use WideWorldImporters;
GO
SELECT
sys.fn_PhysLocFormatter (%%physloc%%),
*
FROM Sales.OrderLines (NOLOCK)
WHERE sys.fn_PhysLocFormatter (%%physloc%%) like '(3:70133%'
GOComme je l'ai dit, c'est lent mĂȘme sur de minuscules tables. J'ai ajoutĂ© NOLOCK Ă la requĂȘte car nous n'avons de toute façon aucune garantie que les donnĂ©es sur lesquelles nous voulons jeter un coup d'Ćil sont exactement les mĂȘmes que celles qui Ă©taient prĂ©sentes au moment oĂč le verrou a Ă©tĂ© dĂ©couvert â donc nous pouvons faire des lectures non fiables.
Mais, hourra, la requĂȘte me retourne ces 25 lignes pour lesquelles notre requĂȘte a luttĂ©.

Assez parlé des verrous PAGE. Que se passe-t-il si nous attendons un verrou KEY ?
2) waitresource=âKEY: 6:72057594041991168 (ce52f92a058c)â = Database_Id, HOBT_Id (le hachage magique qui peut ĂȘtre dĂ©chiffrĂ© Ă l'aide de %%lockres%%, si vous le souhaitez vraiment)
Si votre requĂȘte tente de verrouiller une ligne dans l'index et se retrouve elle-mĂȘme bloquĂ©e, vous obtenez un type d'adresse complĂštement diffĂ©rent.
En dĂ©composant â6:72057594041991168 (ce52f92a058c)â en parties, nous obtenons :
- database_id = 6
- hobt_id = 72057594041991168
- hachage magique = (ce52f92a058c)
2.1) Déchiffrons database_id
Cela fonctionne exactement de la mĂȘme façon que dans l'exemple ci-dessus ! Trouvons le nom de la base de donnĂ©es grĂące Ă la requĂȘte :
SELECT
name
FROM sys.databases
WHERE database_id=6;
GODans mon cas, c'est toujours la mĂȘme .
2.2) Déchiffrons hobt_id
Dans le contexte de la base de donnĂ©es trouvĂ©e, il faut exĂ©cuter une requĂȘte Ă sys.partitions avec quelques jointures qui aideront Ă dĂ©terminer les noms de la table et de l'indexâŠ
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;
GOIl me dit que la requĂȘte Ă©tait en attente sur le verrou Application.Countries, utilisant l'index PK_Application_Countries.
2.3) Maintenant un peu de magie %%lockres%% â si vous voulez dĂ©terminer quel enregistrement a Ă©tĂ© verrouillĂ©
Si je veux vraiment savoir sur quelle ligne le verrou Ă©tait nĂ©cessaire, je peux le dĂ©couvrir grĂące Ă une requĂȘte sur la table elle-mĂȘme. Nous pouvons utiliser la fonction non documentĂ©e %%lockres%% pour trouver l'enregistrement correspondant au hash magique.
Notez que cette requĂȘte va scanner toute la table, et sur de grandes tables, cela peut ne pas ĂȘtre trĂšs agrĂ©able :
SELECT
*
FROM Application.Countries (NOLOCK)
WHERE %%lockres%% = '(ce52f92a058c)';
GO J'ai ajoutĂ© NOLOCK () car les verrous peuvent devenir un problĂšme. Nous voulons juste jeter un Ćil Ă ce qu'il y a maintenant, et non Ă ce qu'il y avait quand la transaction a commencĂ© â je ne pense pas que la cohĂ©rence des donnĂ©es nous importe.
VoilĂ , l'enregistrement pour lequel nous nous sommes battus !

Remerciements et lectures supplémentaires
Je ne me souviens pas qui a décrit pour la premiÚre fois beaucoup de ces choses, mais voici deux articles sur les éléments les moins documentés que vous pourriez apprécier :
- Article de Paul Randal sur (comme nous l'avons fait avec nos données dans le premier exemple)
- Question sur StackOverflow concernant (comme nous avons trouvé les données dans le deuxiÚme exemple). L'une des réponses mÚne à un article .
Source : habr.com
