Suchen Sie in MS SQL Server 2005 nach beschädigtem Objekt anhand der beschädigten Seitenzahl

Eines Tages, als eine der MS SQL Server-Datenbanken auf Suspect umgestellt wurde, gab es eine Fehlermeldung im Protokoll:
Nachricht 7105, Ebene 22, Status 9, Zeile 14
Datenbank-ID 6, Seite (1: 386499), Steckplatz 0 für LOB-Datentypknoten ist nicht vorhanden. Dies wird normalerweise durch Transaktionen verursacht, die nicht festgeschriebene Daten auf einer Datenseite lesen können. Führen Sie DBCC CHECKTABLE aus.

Die Datenbank wurde an Emergency übertragen und versucht, DBCC CHECKDB auszuführen, die Ausführung wurde jedoch sofort unterbrochen:
Nachricht 8921, Ebene 16, Status 1, Zeile 13
Prüfung beendet. Beim Sammeln von Fakten wurde ein Fehler festgestellt. Möglicherweise ist Tempdb nicht genügend Speicherplatz oder eine Systemtabelle inkonsistent. Überprüfen Sie frühere Fehler.
Nachricht 7105, Ebene 22, Status 9, Zeile 13
Datenbank-ID 6, Seite (1: 386499), Steckplatz 0 für LOB-Datentypknoten ist nicht vorhanden. Dies wird normalerweise durch Transaktionen verursacht, die nicht festgeschriebene Daten auf einer Datenseite lesen können. Führen Sie DBCC CHECKTABLE aus.

Der Befehl DBCC CHECKALLOC wurde mit einem ähnlichen Fehler unterbrochen. Alles wurde durch die Tatsache kompliziert, dass SQL Server Version 9.0.1399 war, d.h. RTM, ohne Updates.

Versuche, den TABLOCK-Hinweis zu verwenden und die Transaktionsisolation explizit zu erhöhen, führten zu nichts (es gab genügend Speicherplatz mit tempdb und DBCC CHECKALLOC, wobei WITH ESTIMATEONLY mit demselben Fehler fehlgeschlagen war). Ich wollte SP wirklich nicht auf einen Server mit einer beschädigten Datenbank rollen, und es war völlig unverständlich, mit welchem ​​spezifischen Objekt das Problem bestand. Darüber hinaus schien die DBCC CHECKDB-Nachricht wenig mit der Realität zu tun zu haben, da in msdb.dbo.suspect_pages ein Datensatz vorhanden war, die Seitenzahl sich jedoch von der von DBCC CHECKDB gedruckten unterschied.

Um den Anweisungen von DBCC CHECKDB zu folgen und DBCC CHECKTABLE auszuführen, müssen Sie die Tabelle kennen. Und nach langer Suche wurde eine Anweisung gefunden .
Hinweis
Ich entschuldige mich, dass die Tabellennummern in den Fehlermeldungen und im Code nicht übereinstimmen. Ich habe Fehler aus den Protokollen genommen und danach den Code in einer Testumgebung auf einer anderen Live-Basis ausgeführt.

Wir haben den folgenden Algorithmus verwendet, um die Objekt-ID beider Seiten zu bestimmen - aus DBCC CHECKDB und verdächtigen Seiten. Das Problem war auf der Seite von verdächtigen_Seiten

Das erste, was zu tun ist, ist die Ausführung (im Kontext einer beschädigten Datenbank) der DBCC-SEITE (Datenbank-ID, Datei-ID, Seiten-ID, Druckoption):

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

entweder:

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

Wenn Sie Glück haben (oder auf einer Live-Basis spielen), sehen Sie das Feld Metadaten: Objekt-ID und tatsächlich die gewünschte Objekt-ID:



Wenn Sie jedoch wie wir Pech haben, werden Sie Folgendes sehen:
Metadaten: = In der Offline-Datenbank nicht verfügbar
Wenn keine Metadaten verfügbar sind, geht nicht alles verloren. In diesem Fall benötigen wir das Feld m_objId (AllocUnitId.idObj). Wenn m_objId = 255, besteht das Problem darin, den Artikel zu schließen und nach etwas anderem zu suchen (versuchen Sie, alles zu skripten, was Sie können, und entfernen Sie die Daten, führen Sie DBCC CHECKDB mit den "Wiederherstellungs" -Parametern blind aus usw.).
Der Screenshot zeigt, dass ich m_objId = 9931 habe, d.h. kann weitergehen.

Jetzt müssen Sie einige Berechnungen durchführen, um die ID der Zuordnungseinheit zu berechnen (weitere Informationen zu Zuordnungseinheiten finden Sie hier ):
ID der Zuordnungseinheit = m_objid * 65536 + (2 ^ 56)
In unserem Fall:
ID der Zuordnungseinheit = 9931 * 65536 + (2 ^ 56) = 72057594688765952

Wenn Sie also die Allocation Unit ID kennen, können Sie in der Systemansicht sys.allocation_units sehen, was wir haben:

 SELECT * FROM sys.allocation_units WHERE allocation_unit_id = 72057594688765952 



Und dort, falls Typ = 1 oder 3 (IN_ROW_DATA, ROW_OVERFLOW_DATA), die Spalte container_id = sys.partitions.hobt_id ("Heap-Or-B-Tree ID"), d.h. Sie können die Anforderung ausführen:

 SELECT * FROM sys.partitions WHERE hobt_id = 72057594661437440 



Und hier gibt es bereits die richtige object_id und index_id. Jetzt können Sie sehen, was wir in sys.objects und sys.indexes haben, und einfach ausführen:

 SELECT OBJECT_NAME(object_id) 

Glücklicherweise stellte sich sowohl in der realen Situation als auch hier heraus, dass der Nicht-Cluster-Index bestätigt wurde, nach dessen Umstrukturierung sich alles wieder normalisierte (tatsächlich nein, aber das ist eine andere Geschichte).

Referenzen :
Verwendung von DBCC PAGE
Fehlerbehebung und Behebung von Beschädigungen auf SQL Server-Seitenebene
Was sind Allokationseinheiten?
Suchen eines Tabellennamens aus einer Seiten-ID
sys.allocation_units

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


All Articles