Versehentlicher DBA: Unsicher, warum ich eine unterbrochene Protokollkette habe?

7

Zunächst einmal vielen Dank, dass Sie sich das angesehen haben. Wir haben eine große Datenbank in unserer Produktionsumgebung (1,26 TB), die einige hundert beschädigte Seiten enthält und seit Monaten funktioniert, sodass insgesamt dieselbe Korruption vorliegt der verfügbaren Backups.

Ich wurde in diese späte letzte Woche hineingezogen, da die geplanten Jobs für die Reorganisation von Indizes anscheinend seit einiger Zeit aufgrund der Korruption fehlgeschlagen sind und wir uns jetzt in einem Stadium befinden, in dem die Indizes für die größten und am häufigsten verwendeten Tabellen zwischen 50% und 50% liegen 80% Fragmentierung, die die Anwendungsleistung ernsthaft beeinträchtigt.

Ich habe eine Reihe von Ideen gehabt, wie ich diese Situation beheben könnte (glauben Sie mir, ich bin mehr als offen für Alternativen), und nach dem, was ich gelesen habe, halte ich Folgendes für eine gute Idee:

  1. Erstellen Sie eine komprimierte Sicherung der beschädigten Datenbank aus der Produktion (SQL Server 2008R2), kopieren Sie sie auf unseren (lokalen) Entwicklungsserver (SQL Server 2016) und führen Sie die Reparatur aus (auf dem Produktionssystem ist nicht genügend Speicherplatz für zwei Kopien vorhanden) die beschädigte Datenbank gleichzeitig angehängt).
  2. Stellen Sie zwei Kopien dieser beschädigten Sicherung auf dem Entwicklungsserver wieder her, auf dem genügend Speicherplatz vorhanden ist.
  3. Führen Sie die Reparatur auf dem Entwicklungsserver mit der Option allow_data_loss für eine dieser Datenbank aus und benennen Sie sie in "DbNameHereRepaired" um (bei den meisten beschädigten Seiten, die ich mit DBCC PAGE angesehen habe, waren die Daten ohnehin auf 0x00 gesetzt).
  4. Benennen Sie eine andere Kopie in DbNameHereCorrupt um und versuchen Sie, die Wiederherstellung auf Seitenebene mit dem folgenden Code auszuführen:

        alter database DbNameHereCorrupt set single_user with rollback immediate
    
        --set db to FULL recovery mode
        alter database DbNameHereCorrupt set recovery full
    
        --Declare paths for backups
        declare @fullBackupPath nvarchar(max) = N'D:\Restore\DbNameHereCorrupt-FullBackup.bck'
        declare @tranLogBackupPath nvarchar(max) = N'D:\Restore\DbNameHereCorrupt-LogBackup.bck'
    
        --Take full backup to begin new TLogChain
        backup database DbNameHereCorrupt to disk = @fullBackupPath with init, differential;
    
        --Immediately after whilst in single user mode, begin the t-log chain, this will also put the db in a restoring state
        backup log DbNameHereCorrupt to disk=@tranLogBackupPath with init, norecovery;
    
        --get corrupted pages
        declare @corruptedPages nvarchar(max) = 
        (
            select stuff
            (
                (
                    select ',' + cast(s.file_id as nvarchar(20)) + ':' + cast(s.page_id as nvarchar(20))
                    from msdb.dbo.suspect_pages s
    
                    where s.database_id = 20
    
                    for xml path('')
                ), 1 ,1, ''
            )
        )
    
        --push page-level restore
        restore database DbNameHereCorrupt
        page=@corruptedPages
        from disk=N'D:\Restore\DbNameHereRepaired.bak'
        with norecovery;
    
        -- restore log over db
        restore log DbNameHereCorrupt from disk=@tranLogBackupPath
        with norecovery;
    
        -- put db back into usable state
        restore database DbNameHereCorrupt
        with recovery
    
        --set db to SIMPLE recovery mode
        alter database DbNameHereCorrupt set recovery simple
    
        alter database DbNameHereCorrupt set multi_user

Dies scheint so zu funktionieren, wie ich denke, dass es bis zur Wiederherstellungsanweisung auf Seitenebene funktionieren soll, wo es Fehler gibt, zu sagen:

Meldung 4346, Ebene 16, Status 1, Zeile 35 RESTORE PAGE ist bei Datenbanken, die das einfache Wiederherstellungsmodell verwenden oder die Protokollsicherungskette unterbrochen haben, nicht zulässig.

Dies ist mein erstes Mal, dass ich das vollständige Wiederherstellungsmodell verwende, also habe ich wahrscheinlich etwas falsch gemacht ... Ich kann sehen, wie eine kleine Lücke zwischen dem letzten lsn des Differentials und der Transaktionssicherung aussieht, was ich dort vermute sollte nicht sein.

Kann jemand sehen, was ich hier falsch gemacht habe? Ich habe versucht, Beispielen im Web zu folgen, die alle einem ähnlichen Muster zu folgen scheinen, aber ich denke, ich vermisse etwas?

DB-GB
quelle
Wie viele beschädigte Seiten haben Sie? Wenn Sie mehr als 1000 Seiten haben, schlägt die Wiederherstellung fehl. "Die maximale Anzahl von Seiten, die in einer einzelnen Datei in einer Wiederherstellungssequenz wiederhergestellt werden können, beträgt 1000. Wenn Sie jedoch mehr als eine kleine Anzahl beschädigter Seiten in einer Datei haben, sollten Sie die gesamte Datei anstelle der Seiten wiederherstellen." RESTORE-Anweisungen - Argumente (Transact-SQL) . Und einige ...
John aka hot2use
103 Seiten, 676 Konsistenzfehler. Ich habe es geschafft, die Wiederherstellung der Kopie und die Reparatur mit zulässigem Datenverlust auf unserem Entwicklungsserver auszuführen und anschließend mit dbcc checkdb erneut zu überprüfen - es schien zu funktionieren.
DB-GB
@ TomV Ja, ich konnte anhand der object_ids & page_ids in DBCC CHECK erkennen, dass so ziemlich alles von keiner Anwendung verwendet wird. Es gibt ungefähr 20 bis 30 Seiten mit Daten, die von Wert sein könnten. Glücklicherweise können wir Daten aus der Rohquelle, aus der sie stammen, erneut verarbeiten, um sie wiederherzustellen.
DB-GB
1
Haben Sie in Schritt 1 nur eine vollständige Sicherung von copy_only durchgeführt ?
Andrey Nikolov
@AndreyNikolov Bei dem, den ich im obigen Skript verwende, um zu versuchen, die "beschädigte" Test-Datenbank auf dem Entwicklungsserver in den vollständigen Wiederherstellungsmodus zu versetzen, war dies keine Standardsicherung. Für das ursprüngliche Backup, das ich zuvor aus der Produktion kopiert habe, war das nur copy_only.
DB-GB

Antworten:

3

Ihr Befehl für die vollständige Sicherung

- Führen Sie eine vollständige Sicherung durch, um eine neue TLogChain zu starten

Sicherungsdatenbank DbNameHereCorrupt to disk = @fullBackupPath mit init, different;

macht keine vollständige Sicherung.

DIFFERENTIAL

Wird nur mit BACKUP DATABASE verwendet, gibt an, dass die Datenbank- oder Dateisicherung nur aus den Teilen der Datenbank oder Datei bestehen soll, die seit der letzten vollständigen Sicherung geändert wurden.

Wie in @dbamex erwähnt, verwenden die Befehle full und restore unterschiedliche Dateinamen.

Mija
quelle
Danke mija! Ich habe es ohne das Schlüsselwort different versucht (es wurde nur aus Geschwindigkeitsgründen hinzugefügt, eine vollständige Sicherung dauert 3-4 Stunden). Ja, das war eine Art Absicht, aber nach dem, was @dbamex gesagt hat, ist das auch die Quelle meines Problems :(.
DB-GB
1

Sie springen zu Lösungen, ohne das Problem zuerst zu identifizieren. Wie lautet die Index-ID der beschädigten Seiten? Wenn die Index-ID nicht 0 oder 1 ist, handelt es sich um nicht gruppierte Indizes. Schreiben Sie Skripte, löschen Sie sie und erstellen Sie sie neu. Dies sollte die Beschädigung beheben.

Wenn es sich um die Index-ID 1 (Clustered-Index) oder 0 (Heap) handelt, müssen Sie prüfen, ob Sie mithilfe Ihrer NCIs Deckungsindizes haben, um eine Kopie der Daten zu erstellen. Anschließend können Sie die Tabelle oder den Clustered-Index löschen und neu erstellen Korruption zu beheben.

Wenn Sie die Ausgabe von DBCC CHECKDB veröffentlichen, können Sie möglicherweise andere Lösungen als die Wiederherstellung auf Seitenebene identifizieren.

HandyD
quelle
Fast alles ist -1, 0 oder 1, leider habe ich es geschafft, beim letzten Mal nur Indizes neu zu erstellen, aber diesmal habe ich anscheinend nicht so viel Glück. Nur eine der Tabellen enthält Abdeckungsindizes, und der Abdeckungsindex deckt leider nicht alle Spalten in der Tabelle ab. Aus den Klängen der obigen Kommentare geht hervor, dass eine Wiederherstellung auf Seitenebene (so wie ich es sowieso versuche) möglicherweise nicht möglich ist, ohne viel Glück und einen Weg zu finden, LSNs zu fummeln.
DB-GB