È possibile provare questa procedura per eseguire una query sui file di backup del registro e trovare in quali file di backup del registro un valore specifico di una colonna di una tabella era ancora / presente per ultimo.
Per trovare l'utente, dopo aver trovato nel backup del registro l'ultimo valore esistente, è possibile ripristinare un database fino al backup del registro e quindi seguire la risposta di Mark Storey-Smith .
Alcuni prerequisiti
- sapere quali valori da quali colonne sono state eliminate
- Sono sotto il modello di recupero completo e stanno eseguendo backup del registro
- hai date o identificatori nei tuoi backup di log, come quando usi la soluzione di Ola Hallengren
disconoscimento
Questa soluzione è tutt'altro che impermeabile e richiede molto più lavoro.
Non è stato testato su ambienti di grandi dimensioni, o su qualsiasi ambiente, a parte alcuni piccoli test. L'esecuzione corrente era su SQL Server 2017.
È possibile utilizzare la procedura seguente di Muhammad Imran che ho modificato per funzionare con il contenuto dei backup del registro invece del contenuto del registro di un database live.
In questo modo tecnicamente non si eseguono ripristini, ma si scarica invece il contenuto del registro in una tabella temporanea. Probabilmente sarà ancora lento, ed è molto aperto a bug e problemi. Ma potrebbe funzionare, in teoria ™.
La procedura memorizzata utilizza la fn_dump_dblog
funzione non documentata per leggere i file di registro.
Ambiente di test
Considera questo database, in cui inseriamo alcune righe, eseguiamo 2 backup del log e sul terzo backup del log eliminiamo tutte le righe.
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
La procedura
Puoi trovare e scaricare la procedura memorizzata qui .
Non potrei aggiungerlo qui poiché è più grande del limite del personaggio e renderebbe questa risposta ancora meno chiara di quello che è.
A parte questo, dovresti essere in grado di eseguire la procedura.
Esecuzione della procedura
Un esempio di ciò, quando aggiungo tutti i miei file di registro ( 4
) alla procedura memorizzata ed eseguo la procedura cercando value1
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Questo mi fa:
ID val LogFileName
1 value1 c:\temp\Logs\log3.trn
1 value1 c:\temp\Logs\log1.trn
Dove possiamo trovare quando è avvenuta l'ultima volta un'operazione su value1
, l'eliminazione in log3.trn
.
Alcuni altri dati di test, aggiungendo una tabella con colonne diverse
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
Modifica dei nomi dei file di registro ed esecuzione della procedura
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Risultato
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
Una nuova corsa, alla ricerca dell'intero ( 2
) nella val3
colonna didbo.WrongDeletes2
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes2',
@SearchString = '2',
@SearchColumn = 'Val3',
@LogBackupFolder ='C:\temp\Logs\'
Risultato
Anotherval Val3 Wow LogFileName
value2 2 c c:\temp\Logs\log2.trn
value2 2 c c:\temp\Logs\log3.trn
Applicando la risposta di Mark Storey-Smith
Ora sappiamo che è successo nel terzo file di registro, ripristiniamo fino a quel punto:
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
Esecuzione dell'ultima query nella sua risposta
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]
Risultato per me (amministratore di sistema)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450