Come scoprire chi cancellato alcuni dati di SQL Server
-
16-10-2019 - |
Domanda
Il mio capo ha avuto una query da un cliente ieri chiedendo come avrebbero potuto scoprire chi cancellato alcuni dati nel loro database SQL Server (è l'edizione espressa se quello che conta).
Ho pensato che questo potrebbe essere trovato dal log delle transazioni (purché non fosse stato troncato) - è corretto? E se sì, come si fa a realtà fare per trovare queste informazioni?
Soluzione
Non ho provato fn_dblog su Express, ma se è disponibile di seguito vi darà le operazioni di eliminazione:
SELECT
*
FROM
fn_dblog(NULL, NULL)
WHERE
Operation = 'LOP_DELETE_ROWS'
Prendere l'ID di transazione per le transazioni che ti interessa e identificare il SID che ha avviato la transazione con:
SELECT
[Transaction SID]
FROM
fn_dblog(NULL, NULL)
WHERE
[Transaction ID] = @TranID
AND
[Operation] = 'LOP_BEGIN_XACT'
Quindi identificare l'utente dal SID:
SELECT
*
FROM
sysusers
WHERE
[sid] = @SID
Modifica: Portare che tutti insieme per trovare le eliminazioni su una tabella specificata:
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]
Altri suggerimenti
Se il database è in modalità di recupero completo o se si dispone di backup del log delle transazioni si può provare a leggere questi lettori di log di terze parti che utilizzano.
Si può provare a ApexSQL Log (premio ma ha una versione di prova gratuita) o SQL Log Rescue (gratuito ma sql 2000).
come avrebbero potuto scoprire chi cancellato alcuni dati nel loro database SQL Server
Anche se questa risposta, ha voluto aggiungere che SQL Server ha una traccia di default abilitato e può essere utilizzato per scoprire chi è sceso / alterato gli oggetti.
eventi Oggetto
eventi oggetto includono: Object Altered, oggetto creato e oggetto eliminato
Nota: di SQL Server per impostazione predefinita ha 5 file di traccia, 20 MB ciascuno e non c'è è noto metodo supportato per cambiare questo. Se si dispone di un sistema occupato, i file di traccia possono rotolare troppo veloce (anche poche ore) e potrebbe non essere in grado di catturare alcuni dei cambiamenti.
Eccellente esempio può essere trovato: la traccia di default in SQL Server - la potenza di prestazioni e sicurezza auditing
Si potrebbe provare questa procedura per interrogare i file di backup del registro e di trovare in cui il file di log di backup (s) uno specifico valore di una colonna di una tabella era ancora / ultimo regalo.
Per trovare l'utente, dopo aver trovato in quello che registro di backup l'ultimo valore esiste, è possibile ripristinare un database fino a quel backup del registro e poi seguire Mark Storey-Smith 's risposta.
Alcuni prerequisiti
- so cosa valori da cui colonne sono stati cancellati
- sono sotto il modello di recupero completo e stanno prendendo i backup del log
- avete date o identificatori nel backup del log, ad esempio quando si utilizza Ola La soluzione di Hallengren
responsabilità
Questa soluzione è tutt'altro che impermeabile, e molto di più esigenze di lavoro per andare in esso.
E non è stato testato su ambienti di grandi dimensioni, o anche qualsiasi ambiente a parte alcuni piccoli test. esecuzione corrente era in SQL Server 2017.
Si potrebbe usare sotto procedura da Muhammad Imran che ho modificato per lavorare con i contenuti di backup log al posto del contenuto del registro di un database dal vivo.
In questo modo non si sta facendo tecnicamente ripristini, ma invece il dumping il contenuto del registro in una tabella temporanea. Sarà probabilmente ancora lento, ed è molto aperto a bug e problemi. Ma potrebbe funzionare, in teoria ™.
La stored procedure utilizza la funzione non documentata fn_dump_dblog
per leggere i file di log.
ambiente di test
Si consideri questo database, dove inseriamo alcune righe, prendere 2 backup del log, e al terzo backup del log che elimina 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
È possibile trovare e scaricare la stored procedure qui .
Non ho potuto inserirlo qui dato che è più grande del limite di caratteri, e renderebbe questa risposta ancora meno chiara di quanto non sia.
Oltre a questo, si dovrebbe essere in grado di eseguire la procedura.
Esecuzione della procedura
Un esempio di questo, quando aggiungo tutti i miei file di log (4
) alla stored procedure e eseguire la procedura di ricerca di valore1
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 l'ultima volta che un'operazione su value1
accaduto, la cancellazione in log3.trn
.
Alcuni dati di test più, l'aggiunta di una tabella con diverse colonne
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 e di eseguire la procedura di nuovo
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 pista, alla ricerca di numero intero (2
) nella colonna di val3
dbo.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
Applicazione risposta Mark Storey-Smith s '
Ora sappiamo che è accaduto nel terzo file di log, cerchiamo di ripristinare 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 l'ultima query nella sua risposta ??strong>
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 (sysadmin)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450