Rechercher un objet endommagé par numéro de page endommagé dans MS SQL Server 2005

Un de ces jours, l'une des bases de données MS SQL Server est passée à Suspect, il y avait un message d'erreur dans le journal:
Msg 7105, niveau 22, Ă©tat 9, ligne 14
ID de base de données 6, page (1: 386499), l'emplacement 0 pour le noeud de type de données LOB n'existe pas. Cela est généralement dû à des transactions qui peuvent lire des données non validées sur une page de données. Exécutez DBCC CHECKTABLE.

La base de données a été transférée à Emergency et a tenté d'exécuter DBCC CHECKDB, mais l'exécution a été immédiatement interrompue:
Msg 8921, niveau 16, Ă©tat 1, ligne 13
Vérification terminée. Un échec a été détecté lors de la collecte des faits. Il se peut que tempdb manque d'espace ou qu'une table système soit incohérente. Vérifiez les erreurs précédentes.
Msg 7105, niveau 22, Ă©tat 9, ligne 13
ID de base de données 6, page (1: 386499), l'emplacement 0 pour le noeud de type de données LOB n'existe pas. Cela est généralement dû à des transactions qui peuvent lire des données non validées sur une page de données. Exécutez DBCC CHECKTABLE.

La commande DBCC CHECKALLOC a été interrompue avec une erreur similaire. Tout était compliqué par le fait que SQL Server était la version 9.0.1399, c'est-à-dire RTM, sans aucune mise à jour.

Les tentatives d'utilisation de l'indicateur TABLOCK et d'augmentation explicite du niveau d'isolement des transactions n'ont abouti à rien (il y avait suffisamment d'espace disque avec tempdb et DBCC CHECKALLOC avec WITH ESTIMATEONLY a échoué avec la même erreur). Je ne voulais vraiment pas faire rouler SP sur un serveur avec une base de données endommagée, et c'était complètement incompréhensible avec quel objet spécifique était le problème. De plus, il semblait que le message DBCC CHECKDB avait peu à voir avec la réalité, car il y avait un enregistrement dans msdb.dbo.suspect_pages, mais le numéro de page était différent de celui imprimé par DBCC CHECKDB.

Pour suivre les instructions DBCC CHECKDB et exécuter DBCC CHECKTABLE, vous devez connaître la table. Et après une longue recherche, une instruction a été trouvée .
Remarque
Je m'excuse que les numéros de table dans les messages d'erreur et dans le code ne correspondent pas. J'ai pris des erreurs dans les journaux, puis j'exécute le code dans un environnement de test sur une autre base en direct.

Nous avons utilisé l'algorithme ci-dessous pour déterminer l'id_objet des deux pages - à partir de DBCC CHECKDB et suspect_pages. Le problème était dans la page de suspect_pages

La première chose à faire est d'exécuter (dans le contexte d'une base de données endommagée) est DBCC PAGE (database_id, file_id, page_id, printopt):

DBCC TRACEON (3604); DBCC PAGE(5, 1, 3242342, 0) DBCC TRACEOFF (3604); 

soit:

 DBCC PAGE(5, 1, 3242342, 0) WITH TABLERESULTS. 

Si vous avez de la chance (ou que vous jouez sur une base live), vous verrez par conséquent le champ Metadata: ObjectId et, en fait, le object_id souhaité:



Cependant, si vous, comme nous, n'avez pas de chance, vous verrez ce qui suit:
Métadonnées: = non disponible dans la base de données hors ligne
Si les métadonnées ne sont pas disponibles, tout n'est pas perdu, dans ce cas, nous avons besoin du champ m_objId (AllocUnitId.idObj). Si m_objId = 255, le problème est, fermez l'article et cherchez autre chose (essayez de script tout ce que vous pouvez et supprimez les données, exécutez DBCC CHECKDB avec les paramètres de "récupération" aveuglément, etc.).
La capture d'Ă©cran montre que j'ai m_objId = 9931, c'est-Ă -dire peut continuer.

Vous devez maintenant effectuer quelques calculs pour calculer l'ID d'unité d'allocation (vous trouverez plus d'informations sur les unités d'allocation ici ):
ID de l'unité d'allocation = m_objid * 65536 + (2 ^ 56)
Dans notre cas:
ID de l'unité d'allocation = 9931 * 65536 + (2 ^ 56) = 72057594688765952

Ainsi, connaissant l'ID d'unité d'allocation, vous pouvez voir ce que nous avons dans la vue système sys.allocation_units :

 SELECT * FROM sys.allocation_units WHERE allocation_unit_id = 72057594688765952 



Et là, dans le cas où type = 1 ou 3 (IN_ROW_DATA, ROW_OVERFLOW_DATA), la colonne container_id = sys.partitions.hobt_id ("Heap-Or-B-Tree ID"), c'est-à-dire Vous pouvez exécuter la demande:

 SELECT * FROM sys.partitions WHERE hobt_id = 72057594661437440 



Et ici, il y a déjà les object_id et index_id corrects. Vous pouvez maintenant voir ce que nous avons dans sys.objects et sys.indexes, et simplement exécuter:

 SELECT OBJECT_NAME(object_id) 

Heureusement, dans la situation réelle comme ici, l'indice non cluster s'est avéré être confirmé, après une restructuration dont tout est revenu à la normale (en fait non, mais c'est une autre histoire).

Références :
Comment utiliser DBCC PAGE
DĂ©pannage et correction de la corruption au niveau de la page SQL Server
Que sont les unités d'allocation?
Recherche d'un nom de table Ă  partir d'un ID de page
sys.allocation_units

Source: https://habr.com/ru/post/fr430824/


All Articles