Blog

Retten einer beschädigten Datenbank

Henrik
Werkstudent

Im Laufe des Betriebs einer Datenbank kann es vorkommen, dass diese zu einem Zeitpunkt abstürzt. Mit den richtigen Vorsichtsmaßnahmen stellt das aber kein Problem dar. Entweder wurde über ein Cluster die Arbeit bereits umverteilt, oder es kann ein Backup geladen werden, sodass kaum bis keine Daten verloren gehen. Ein Problem besteht nur, wenn zu selten Backups erstellt werden oder die Datenbank im Simple-Recovery Modus betrieben wird. Der offensichtliche Worst Case ist, wenn Dateien der Datenbank mitsamt des Backups beschädigt werden. Wie man dieses Problem lösen kann, erklären wir in den folgenden Abschnitten.

Ausgangslage

Vor einiger Zeit kam ein Kunde mit genau diesem Problem auf uns zu. Die Ursache des Problems galt es jetzt zu lösen. Es handelte sich um eine Datenbank von SQL Server 2016. Diese lief mit einem angepassten Kompatibilitätslevel auf einer SQL Server 2019 Instanz. Es wurde am Morgen entdeckt, dass diese Datenbank über Nacht ausgefallen war. Jedoch gab es ein Problem damit, diese wieder online zu nehmen. Offenbar waren zudem einige Daten beschädigt. Ein Laden des Backups löste die Situation auch nicht, da auch hier die fehlerhaften Daten enthalten waren. Als Konsequenz musste die Datenbank zunächst auf einen Stand zurückgesetzt werden, der einige Wochen alt war. Dadurch gehen alle zwischenzeitlich vorgenommenen Änderungen verloren. Das gilt für geänderte Daten, aber auch für neu erstellte. Die folgenden Schritte haben wir für die SQL Server Versionen 2019 und 2022 getestet.

Analyse

Damit wir uns ein genaueres Bild des Problems machen konnten, haben wir die beschädigte Datenbank in eine Testumgebung gezogen. Ein erster Schritt der Analyse ist DBCC CHECKDB auszuführen. Wie das geht, haben wir bereits in einem älteren Artikel beschrieben. Wir erhielten Fehlermeldungen, dass Indizes zu keinen Datenreihen passen und dass Schlüssel in den Indizes fehlen. Ein Versuch diese Indizes zu reparieren schlug fehl, da dies nicht das einzige Problem war. Neben den beschädigten DB-Dateien, war auch die Log-Datei beschädigt. Aus diesem Grund haben wir eine neue Datenbank mit der .mdf Datei erstellt. Dadurch kann eine neue saubere Log-Datei erstellt werden. Folgenden Code, haben wir dafür genutzt:

CREATE DATABASE ON
(FILENAME = '\.mdf')
FOR ATTACH_REBUILD_LOG

Reparatur

Somit haben wir das erste Problem, nämlich, dass die DB nicht geöffnet werden konnte, gelöst. Jedoch sind immer noch Daten/Tabellen und Indizes beschädigt. Mit dem Befehl

DBCC CHECKDB ('dbName', REPAIR_ALLOW_DATA_LOSS)

lassen sich zumindest die fehlerhaften Daten/Tabellen reparieren, jedoch können dabei Daten verloren gehen. Da beim Reparieren der Indizes keine Daten verloren gehen, lösen wir zunächst dieses Problem, bevor wir die fehlerhaften Daten und Tabellen reparieren.

Msg 2511, Level 16, State 1, Line 24
Table error: Object ID 1566628624, index ID 1, partition ID 72057594317307904, alloc unit ID 72057594368491520 (type In-row data). Keys out of order on page (1:222213), slots 7 and 8.
Msg 2511, Level 16, State 1, Line 24
Table error: Object ID 1566628624, index ID 1, partition ID 72057594317307904, alloc unit ID 72057594368491520 (type In-row data). Keys out of order on page (1:320059), slots 157 and 158.
Msg 8981, Level 16, State 1, Line 24
Table error: Object ID 1566628624, index ID 1, partition ID 72057594317307904, alloc unit ID 72057594368491520 (type In-row data). The next pointer of (1:359422) refers to page (1:242284). Neither (1:242284) nor its parent were encountered. Possible bad chain linkage.
Msg 8978, Level 16, State 1, Line 24
Table error: Object ID 1566628624, index ID 1, partition ID 72057594317307904, alloc unit ID 72057594368491520 (type In-row data). Page (1:274476) is missing a reference from previous page (1:187530). Possible chain linkage problem.
Msg 8935, Level 16, State 1, Line 24
Table error: Object ID 1566628624, index ID 1, partition ID 72057594317307904, alloc unit ID 72057594368491520 (type In-row data). The previous link (1:187530) on page (1:313738) does not match the previous page (1:274476) that the parent (1:320059), slot 159 expects for this page.
Msg 8935, Level 16, State 1, Line 24
Table error: Object ID 1566628624, index ID 1, partition ID 72057594317307904, alloc unit ID 72057594368491520 (type In-row data). The previous link (1:242283) on page (1:359422) does not match the previous page (1:359421) that the parent (1:222213), slot 8 expects for this page.
Msg 8978, Level 16, State 1, Line 24
Table error: Object ID 1566628624, index ID 1, partition ID 72057594317307904, alloc unit ID 72057594368491520 (type In-row data). Page (1:359422) is missing a reference from previous page (1:242283). Possible chain linkage problem.
Msg 8935, Level 16, State 1, Line 24
Table error: Object ID 1566628624, index ID 1, partition ID 72057594317307904, alloc unit ID 72057594368491520 (type In-row data). The previous link (1:359421) on page (1:359423) does not match the previous page (1:359422) that the parent (1:222213), slot 9 expects for this page.
...
...
Msg 8951, Level 16, State 1, Line 24
Table error: table '' (ID 2037582297). Data row does not have a matching index row in the index '' (ID 4). Possible missing or invalid keys for the index row matching:
Msg 8955, Level 16, State 1, Line 24
Data row (1:134849:79) identified by (Oid = 'C67C60EC-9BA3-4946-B87F-FE9B105BA784') with index values 'CurrentValue = '4018019F-8F9E-4272-B686-72FD388444AA' and Oid = 'C67C60EC-9BA3-4946-B87F-FE9B105BA784''.
Msg 8952, Level 16, State 1, Line 24
Table error: table '' (ID 2037582297). Index row in index '' (ID 4) does not match any data row. Possible extra or invalid keys for:
Msg 8956, Level 16, State 1, Line 24
Index row (1:236776:43) with values (CurrentValue = '93BD5250-6EC2-4CAC-A812-375E8138AC85' and Oid = 'C67C60EC-9BA3-4946-B87F-FE9B105BA784') pointing to the data row identified by (Oid = 'C67C60EC-9BA3-4946-B87F-FE9B105BA784').

Dies ist der Auszug der Analyse durch DBCC CHECKDB. Hier erkennen wir, welche Objekte die Probleme verursachen. Es kann durchaus vorkommen (wie in der ersten Message) dass keine Namen angegeben werden, sondern nur Object IDs. Mithilfe dieser ID kann das richtige Objekt gefunden werden. Wir verwenden dafür folgenden Befehl:

SELECT name FROM sys.objects WHERE object_id =

Mit dieser Info versuchen wir den entsprechenden Index neu zu bauen (Index Rebuild). Jedoch klappte das in diesem Fall nicht. Also löschten wir den Index und erstellen ihn neu. In der SSMS Oberfläche kann man mit Rechtsklick auf den Index das passende Skript erzeugen. Das sieht folgendermaßen aus:

DROP INDEX [dbo].[tableName].[indexName]
CREATE NONCLUSTERED INDEX [indexName] ON [dbo].[tableName]
(
[CurrentValue] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

Dieser Vorgang muss für jeden Index vorgenommen werden, der in der Fehlernachricht von DBCC CHECKDB steht. Eine erneute Analyse mit DBCC CHECKDB stellt fest, ob noch weitere Probleme bestehen. Sollte das der Fall sein, muss eventuell auf den Reparaturbefehl von oben zurückgegriffen werden. Wenn alle Probleme behoben sind, lässt sich die Datenbank wieder problemlos online stellen. Als Vorsichtsmaßnahme setzen wir die Datenbank direkt in den Full Recovery Modus und erstellen ein neues Backup. Damit hatte unser Kunde wieder die aktuelle Datenbank und das passende Backup dazu.

Fazit

Mit diesen Schritten haben wir Ihnen zeigen können, dass auch bei einer beschädigten Datenbank nicht alle Hoffnung verloren ist. Mit den gezeigten Mitteln kann so manches System wieder gerettet werden. Natürlich ist das Vorgehen für jede Datenbank individuell. Außerdem soll gesagt sein, dass dieses Szenario mit einem richtigen Backupplan verhindert werden kann. Wenn Sie einen solchen Plan benötigen oder Fragen dazu haben, können Sie einen unverbindlichen Termin über unser Kontaktformular ausmachen. Unsere Expert:Innen stehen Ihnen gerne zur Verfügung.

Interesse geweckt?
Vielen Dank! Wir haben Ihre Anfrage erhalten!
Oops! Beim Senden ist etwas schiefgegangen, versuche es erneut.