waitresource = "PAGE: 6: 3: 70133"
waitresource = "CLĂ: 6: 72057594041991168 (ce52f92a058c)"
Parfois, il y aura plus d'informations dans ce XML géant que vous apprenez (les graphiques bloqués contiennent une liste de ressources qui vous aide à trouver les noms d'objet et d'index), mais pas toujours.
Ce texte vous aidera à les déchiffrer.
Toutes les informations qui sont ici se trouvent sur Internet à divers endroits, elles sont simplement trÚs diffusées! Je veux tout mettre ensemble - de DBCC PAGE à hobt_id et aux fonctions non documentées %% physloc %% et %% lockres %%.
Parlons d'abord de l'attente des verrous PAGE, puis passons aux verrous KEY.
1) waitresource = "PAGE: 6: 3: 70133" = Database_Id: FileId: PageNumber
Si votre requĂȘte attend un verrou PAGE, SQL Server vous donnera l'URL de cette page.
En décomposant "PAGE: 6: 3: 70133", nous obtenons:
- id_base_de_données = 6
- data_file_id = 3
- page_numer = 70133
1.1) DĂ©crypter database_id
Trouvons le nom de la base de donnĂ©es Ă l'aide de la requĂȘte:
SELECT
name
FROM sys.databases
WHERE database_id=6;
GO
Il s'agit de la base de données publique WideWorldImporters sur mon serveur SQL.
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 le nom du fichier vous intĂ©resse, vous pouvez le trouver en exĂ©cutant une requĂȘte dans le contexte du DB trouvĂ©, en remplaçant data_file_id dans cette requĂȘte:
USE WideWorldImporters;
GO
SELECT
name,
physical_name
FROM sys.database_files
WHERE file_id = 3;
GO
Dans la base de donnĂ©es WideWorldImporters, il s'agit d'un fichier nommĂ© WWI_UserData et il a Ă©tĂ© restaurĂ© dans mon C: \ MSSQL \ DATA \ WideWorldImporters_UserData.ndf. (Oups, vous m'avez surpris en train de mettre des fichiers sur le disque systĂšme! Non! C'Ă©tait gĂȘnant).
1.3) Obtenez le nom de l'objet Ă partir de la PAGE DBCC
Nous savons maintenant que la page # 70133 du fichier de données 3 appartient à la base de données WorldWideImporters. Nous pouvons regarder le contenu de cette page en utilisant la PAGE DBCC non documentée et l'indicateur de trace 3604.
Remarque: Je préfÚre utiliser la PAGE DBCC sur une sauvegarde restaurée à partir d'une sauvegarde quelque part sur un serveur différent, car c'est une chose non documentée. Dans certains cas, cela peut conduire à la création d'un dump ( commentaire du traducteur - le lien, malheureusement, ne mÚne nulle part, mais à en juger par l'url, on parle 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 faisant défiler les résultats, vous pouvez 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;
GO
Et maintenant, nous voyons que l'attente sur le verrou Ă©tait sur l'index PK_Sales_OrderLines de la table Sales.OrderLines.
Remarque: dans SQL Server 2014 et versions ultĂ©rieures, le nom de l'objet peut Ă©galement ĂȘtre trouvĂ© Ă l'aide du DMO non documentĂ© sys.dm_db_database_page_allocations. Mais vous devez interroger chaque page de la base de donnĂ©es, ce qui n'a pas l'air trĂšs cool pour les grandes bases de donnĂ©es, j'ai donc utilisĂ© DBCC PAGE.
1.4) Pouvez-vous voir les données sur la page qui a été bloquée?
Nuuu, oui. Mais ... ĂȘtes-vous sĂ»r que vous en avez vraiment besoin?
C'est lent mĂȘme sur de petites tables. Mais c'est plutĂŽt cool, donc puisque vous avez lu jusqu'ici ... parlons de %% physloc %%!
%% physloc %% est un morceau de magie non documenté qui renvoie un identifiant physique pour chaque entrée. Vous pouvez utiliser %% physloc %% avec sys.fn_PhysLocFormatter dans SQL Server 2008 et versions ultérieures .
Maintenant que nous savons que nous voulions bloquer la page dans Sales.OrderLines, nous pouvons afficher toutes les donnĂ©es de cette table, qui sont stockĂ©es dans le fichier de donnĂ©es # 3 Ă la page # 70133, Ă l'aide de la requĂȘte suivante:
Use WideWorldImporters;
GO
SELECT
sys.fn_PhysLocFormatter (%%physloc%%),
*
FROM Sales.OrderLines (NOLOCK)
WHERE sys.fn_PhysLocFormatter (%%physloc%%) like '(3:70133%'
GO
Comme je l'ai dit - c'est lent mĂȘme sur de petites tables. J'ai ajoutĂ© NOLOCK Ă la requĂȘte car nous n'avons toujours aucune garantie que les donnĂ©es que nous voulons regarder sont exactement les mĂȘmes que lorsque le verrou a Ă©tĂ© trouvĂ© - afin que nous puissions faire des lectures incorrectes en toute sĂ©curitĂ©.
Mais, hourra, la requĂȘte me renvoie les mĂȘmes 25 lignes pour lesquelles notre requĂȘte s'est battue.
Assez parlé des verrous PAGE. Et si nous attendons un verrou KEY?
2) waitresource = "KEY: 6: 72057594041991168 (ce52f92a058c)" = Database_Id, HOBT_Id (hash magique qui peut ĂȘtre dĂ©chiffrĂ© avec %% lockres %% si vous le souhaitez vraiment)
Si votre requĂȘte tente de verrouiller une entrĂ©e d'index et se verrouille d'elle-mĂȘme, vous obtenez un type d'adresse complĂštement diffĂ©rent.
En décomposant «6: 72057594041991168 (ce52f92a058c)» en plusieurs parties, nous obtenons:
- id_base_de_données = 6
- hobt_id = 72057594041991168
- hachage magique = (ce52f92a058c)
2.1) DĂ©crypter database_id
Cela fonctionne exactement de la mĂȘme maniĂšre que dans l'exemple ci-dessus! Recherchez le nom de la base de donnĂ©es Ă l'aide de la requĂȘte:
SELECT
name
FROM sys.databases
WHERE database_id=6;
GO
Dans mon cas, il s'agit de la mĂȘme base de donnĂ©es WideWorldImporters .
2.2) DĂ©crypter le hobt_id
Dans le contexte de la base de donnĂ©es trouvĂ©e, vous devez exĂ©cuter une requĂȘte sur sys.partitions avec quelques jointures qui vous aideront Ă dĂ©terminer les noms de table et d'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;
GO
Il m'indique que la demande Ă©tait en attente sur le verrou Application.Countries Ă l'aide de l'index PK_Application_Countries.
2.3) Maintenant un peu de magie %% lockres %% - si vous voulez savoir quel enregistrement a été verrouillé
Si je veux vraiment savoir sur quelle ligne le verrou Ă©tait nĂ©cessaire, je peux le comprendre en interrogeant la table elle-mĂȘme. Nous pouvons utiliser la fonction %% lockres %% non documentĂ©e pour trouver l'entrĂ©e qui correspond au hachage magique.
Notez que cette requĂȘte analysera la table entiĂšre, et sur les grandes tables, cela peut ne pas ĂȘtre amusant du tout:
SELECT
*
FROM Application.Countries (NOLOCK)
WHERE %%lockres%% = '(ce52f92a058c)';
GO
J'ai ajoutĂ© NOLOCK ( sur les conseils de Klaus Aschenbrenner sur Twitter ) car le blocage peut ĂȘtre un problĂšme. Nous voulons simplement voir ce qu'il y a maintenant, et non ce qu'il y avait au dĂ©but de la transaction - je ne pense pas que la cohĂ©rence des donnĂ©es soit importante pour nous.
Voila, le record pour lequel nous nous sommes battus!
Remerciements et lectures complémentaires
Je ne me souviens pas qui a été le premier à décrire beaucoup de ces choses, mais voici deux articles sur les choses les moins documentées que vous pourriez aimer:
- Message de Paul Randal sur %% physloc %% et sys.fn_PhysLocFormatter (comme nous le faisons pour nos données dans le premier exemple)
- Une question sur StackOverflow sur l' utilisation de %% lockres %% (comme nous avons trouvé les données dans le deuxiÚme exemple). L'une des réponses va au message de Grant Fritchey sur %% lockres %%, écrit en 2010 .