So finden Sie heraus, wer einige Daten SQL Server gelöscht hat
-
16-10-2019 - |
Frage
Mein Chef hatte gestern eine Abfrage von einem Kunden und fragte, wie er herausfinden kann, wer einige Daten in seiner SQL Server -Datenbank gelöscht hat (es ist die Express Edition, wenn dies wichtig ist).
Ich dachte, dies könnte aus dem Transaktionsprotokoll gefunden werden (vorausgesetzt, es war nicht verkürzt worden) - ist das richtig? Und wenn ja, wie können Sie diese Informationen tatsächlich herausfinden?
Lösung
Ich habe fn_dblog auf Express nicht ausprobiert, aber wenn es verfügbar ist, erhalten Sie nach Folgen von Löschen von Vorgängen:
SELECT
*
FROM
fn_dblog(NULL, NULL)
WHERE
Operation = 'LOP_DELETE_ROWS'
Nehmen Sie die Transaktions -ID für Transaktionen, an denen Sie interessiert sind, und identifizieren Sie den SID, der die Transaktion mit:
SELECT
[Transaction SID]
FROM
fn_dblog(NULL, NULL)
WHERE
[Transaction ID] = @TranID
AND
[Operation] = 'LOP_BEGIN_XACT'
Identifizieren Sie dann den Benutzer aus dem SID:
SELECT
*
FROM
sysusers
WHERE
[sid] = @SID
Bearbeiten: Bringen Sie das alles zusammen, um Deletten in einer bestimmten Tabelle zu finden:
DECLARE @TableName sysname
SET @TableName = 'dbo.Table_1'
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]
Andere Tipps
Wenn die Datenbank im vollständigen Wiederherstellungsmodus ist oder über Transaktionsprotokollsicherungen verfügt, können Sie versuchen, diese mit Lesern von Drittanbietern zu lesen.
Du kannst es versuchen ApexSQL -Protokoll (Prämie, hat aber eine kostenlose Testversion) oder SQL Log Rescue (Nur frei, aber nur SQL 2000).
Wie sie herausfinden konnten, wer einige Daten in ihrer SQL Server -Datenbank gelöscht hat
Obwohl dies beantwortet wird, wollte der SQL -Server eine Standardverfolgung aktiviert und es kann verwendet werden, um herauszufinden, wer die Objekte fallen gelassen/geändert hat.
Objektereignisse
Zu den Objektereignissen gehören: Objekt geändert, Objekt Erstellt und Objekt gelöscht
Hinweis: SQL Server verfügt standardmäßig über 5 Trace -Dateien, jeweils 20 MB, und es gibt keine unterstützte Methode, um dies zu ändern. Wenn Sie ein geschäftiges System haben, können die Trace -Dateien (sogar innerhalb von Stunden) viel zu schnell überrollen, und Sie können möglicherweise nicht einige der Änderungen fangen.
Hervorragendes Beispiel kann gefunden werden: Die Standardverfolgung in SQL Server - die Leistung der Leistung und Sicherheitsprüfung
Sie können diese Prozedur versuchen, die Protokollsicherungsdateien abzufragen und zu finden, in welcher Protokollsicherungsdatei (n) ein bestimmter Wert einer Spalte einer Tabelle noch vorhanden war.
Um den Benutzer zu finden, können Sie eine Datenbank bis zu dieser Protokollsicherung wiederherstellen und dann folgen Mark Storey-SmithAntwort.
Einige Voraussetzungen
- Wissen Sie, welche Werte aus den Spalten gelöscht wurden
- Befinden sich unter dem vollständigen Wiederherstellungsmodell und nehmen Protokollsicherungen vor
- Sie haben Daten oder Kennungen in Ihren Protokollsicherungen, beispielsweise bei der Verwendung von Ola Hallengrens Lösung
Haftungsausschluss
Diese Lösung ist alles andere als wasserdicht, und es muss noch viel mehr Arbeit in sie eingehen.
Es wurde weder in großen Umgebungen noch Umgebungen getestet, abgesehen von einigen kleinen Tests. Der aktuelle Lauf war auf SQL Server 2017.
Sie könnten unten verwenden Verfahren aus Muhammad Imran dass ich geändert habe, um mit dem Inhalt von zu arbeiten Protokollsicherungen Anstelle des Inhalts eines Live -Datenbankprotokolls.
Die gespeicherte Prozedur verwendet die undokumentierte fn_dump_dblog
Funktion zum Lesen der Protokolldateien.
Testumgebung
Betrachten Sie diese Datenbank, in der wir einige Zeilen einfügen, 2 Protokollsicherungen nehmen und auf 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
Das Verfahren
Sie können die gespeicherte Prozedur finden und herunterladen hier.
Ich konnte es hier nicht hinzufügen, da es größer ist als die Charakterlimit und würde diese Antwort noch weniger klar machen als es ist.
Abgesehen davon sollten Sie in der Lage sein, das Verfahren auszuführen.
Ausführen des Verfahrens
Ein Beispiel dafür, wenn ich alle meine Protokolldateien hinzufüge (4
) in die gespeicherte Prozedur und führen Sie das Verfahren aus, die nach Wert 1 suchen1
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:
ID val LogFileName
1 value1 c:\temp\Logs\log3.trn
1 value1 c:\temp\Logs\log1.trn
Wo wir finden können, wenn das letzte Mal eine Operation eingeschaltet wird value1
passiert, das lösche in log3.trn
.
Einige weitere Testdaten, die eine Tabelle mit verschiedenen Spalten hinzufügen
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 der Prozedur
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, auf der Suche nach der Ganzzahl (2
) in dem val3
Säule von dbo.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
Bewirbt sich Mark Storey-SmithAntwort
Wir wissen jetzt, dass es in der dritten Protokolldatei passiert ist. Lassen Sie uns bis zu diesem Zeitpunkt 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
Die letzte Frage in seiner Antwort ausführen
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