Mit dieser Prozedur können Sie die Protokollsicherungsdateien abfragen und feststellen, in welchen Protokollsicherungsdateien ein bestimmter Wert einer Tabellenspalte noch bzw. zuletzt vorhanden war.
Um den Benutzer zu finden, nachdem Sie in welcher Protokollsicherung den zuletzt vorhandenen Wert gefunden haben, können Sie eine Datenbank bis zu dieser Protokollsicherung wiederherstellen und dann Mark Storey-Smiths Antwort folgen .
Einige Voraussetzungen
- wissen, welche Werte aus welchen Spalten gelöscht wurden
- Sind unter dem vollständigen Wiederherstellungsmodell und führen Protokollsicherungen durch
- Ihre Protokollsicherungen enthalten Daten oder Kennungen, z. B. bei der Verwendung der Lösung von Ola Hallengren
Haftungsausschluss
Diese Lösung ist weit davon entfernt, wasserdicht zu sein, und es muss noch viel mehr Arbeit aufgewendet werden.
Es wurde nicht in großen Umgebungen oder sogar in anderen Umgebungen getestet, mit Ausnahme einiger kleinerer Tests. Die aktuelle Ausführung erfolgte auf SQL Server 2017.
Sie können das folgende Verfahren von Muhammad Imran verwenden , das ich geändert habe, um mit dem Inhalt von Protokollsicherungen anstelle des Inhalts des Protokolls einer Live-Datenbank zu arbeiten.
Auf diese Weise führen Sie technisch gesehen keine Wiederherstellungen durch, sondern sichern den Protokollinhalt in einer temporären Tabelle. Es wird wahrscheinlich immer noch langsam sein und ist sehr offen für Fehler und Probleme. Aber theoretisch könnte es funktionieren.
Die gespeicherte Prozedur verwendet die undokumentierte fn_dump_dblog
Funktion, um die Protokolldateien auszulesen.
Testumgebung
Betrachten Sie diese Datenbank, in der wir einige Zeilen einfügen, zwei Protokollsicherungen durchführen und bei der dritten Protokollsicherung alle Zeilen löschen.
CREATE DATABASE WrongDeletesDatabase
GO
USE WrongDeletesDatabase
GO
BACKUP DATABASE WrongDeletesDatabase TO DISK ='c:\temp\Full.bak'
ALTER DATABASE WrongDeletesDatabase SET RECOVERY FULL
GO
CREATE TABLE dbo.WrongDeletes(ID INT, val varchar(255))
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (1,'value1')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (2,'value2')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log2.trn'
GO
DELETE FROM dbo.WrongDeletes
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log3.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (3,'value3')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log4.trn'
GO
Der Ablauf
Sie können die gespeicherte Prozedur hier finden und herunterladen .
Ich konnte es hier nicht hinzufügen, da es größer als die Zeichenbegrenzung ist, und würde diese Antwort noch unklarer machen, als es ist.
Abgesehen davon sollten Sie in der Lage sein, die Prozedur auszuführen.
Prozedur ausführen
Ein Beispiel dafür, wenn ich alle meine Protokolldateien ( 4
) zur gespeicherten Prozedur hinzufüge und die Prozedur auf der Suche nach value1 ausführe
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Das bringt mich auf:
ID val LogFileName
1 value1 c:\temp\Logs\log3.trn
1 value1 c:\temp\Logs\log1.trn
Wo wir finden können, wann das letzte Mal eine Operation value1
stattgefunden hat, ist das Löschen in log3.trn
.
Weitere Testdaten, Hinzufügen einer Tabelle mit verschiedenen Spalten
CREATE TABLE dbo.WrongDeletes2(Wow varchar(255), Anotherval varchar(255),Val3 int)
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (1,'value1')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('b','value1',1)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log1_1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (2,'value2')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('c','value2',2)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log2_1.trn'
GO
DELETE FROM dbo.WrongDeletes
DELETE FROM dbo.WrongDeletes2
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log3_1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (3,'value3')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('d','value3',3)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log4_1.trn'
GO
Ändern der Protokolldateinamen und erneutes Ausführen des Vorgangs
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Ergebnis
ID val LogFileName
1 value1 c:\temp\Logs\log1_1.trn
1 value1 c:\temp\Logs\log3_1.trn
1 value1 c:\temp\Logs\log3_1.trn
Ein neuer Lauf, der nach der Ganzzahl ( 2
) in der val3
Spalte von suchtdbo.WrongDeletes2
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes2',
@SearchString = '2',
@SearchColumn = 'Val3',
@LogBackupFolder ='C:\temp\Logs\'
Ergebnis
Anotherval Val3 Wow LogFileName
value2 2 c c:\temp\Logs\log2.trn
value2 2 c c:\temp\Logs\log3.trn
Anwenden der Antwort von Mark Storey-Smith
Wir wissen jetzt, dass es in der dritten Protokolldatei passiert ist, lassen Sie uns bis zu diesem Punkt wiederherstellen:
USE master
GO
ALTER DATABASE WrongDeletesDatabase SET OFFLINE WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE WrongDeletesDatabase SET ONLINE
GO
RESTORE DATABASE WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\Full.bak' WITH NORECOVERY,REPLACE
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log1.trn' WITH NORECOVERY
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log2.trn' WITH NORECOVERY
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log3.trn' WITH RECOVERY
GO
USE WrongDeletesDatabase
GO
Ausführen der letzten Abfrage in seiner Antwort
SELECT
u.[name] AS UserName
, l.[Begin Time] AS TransactionStartTime
FROM
fn_dblog(NULL, NULL) l
INNER JOIN
(
SELECT
[Transaction ID]
FROM
fn_dblog(NULL, NULL)
WHERE
AllocUnitName LIKE @TableName + '%'
AND
Operation = 'LOP_DELETE_ROWS'
) deletes
ON deletes.[Transaction ID] = l.[Transaction ID]
INNER JOIN
sysusers u
ON u.[sid] = l.[Transaction SID]
Ergebnis für mich (Sysadmin)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450