Můj šéf měl včera dotaz od zákazníka s dotazem, jak by mohl zjistit, kdo odstranil některá data v jejich databázi SQL Server (pokud je to důležité, jedná se o expresní vydání).
Myslel jsem, že to lze najít z protokolu transakcí (za předpokladu, že nebyl zkrácen) - je to správné? A pokud ano, jak se vlastně snažíte najít tyto informace?
Nezkoušel jsem fn_dblog na Express, ale pokud je k dispozici, následující vám umožní operace odstranění:
SELECT
*
FROM
fn_dblog(NULL, NULL)
WHERE
Operation = 'LOP_DELETE_ROWS'
Vezměte ID transakce pro transakce, které vás zajímají, a identifikujte SID, které transakci zahájilo:
SELECT
[Transaction SID]
FROM
fn_dblog(NULL, NULL)
WHERE
[Transaction ID] = @TranID
AND
[Operation] = 'LOP_BEGIN_XACT'
Poté identifikujte uživatele ze SID:
SELECT
*
FROM
sysusers
WHERE
[sid] = @SID
Úpravy: Spojte všechny dohromady a najděte mazání v určené tabulce:
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]
Pokud je databáze v úplném režimu obnovy nebo pokud máte zálohy protokolu transakcí, můžete je zkusit přečíst pomocí čteček protokolu třetích stran.
Můžete zkusit ApexSQL Log (prémiový, ale má zkušební verzi zdarma) nebo SQL Log Rescue (zdarma, ale pouze SQL 2000).
jak mohli zjistit, kdo odstranil některá data v jejich databázi SQL Server
Přestože je zodpovězeno, chtěli jsme přidat, že SQL Server má povoleno výchozí trasování a lze jej použít ke zjištění, kdo zrušil/změnil objekty.
Události objektu
Události objektu zahrnují: Object Altered, Object Created a Object Deleted
poznámka: SQL Server ve výchozím nastavení obsahuje 5 trasovacích souborů, každý o 20 MB a není známa žádná podporovaná metoda změny. Pokud máte zaneprázdněný systém, soubory trasování se mohou převrátit příliš rychle (i během několika hodin) a některé změny pravděpodobně nebudete moci zachytit.
Vynikající příklad lze nalézt: Výchozí trasování v SQL Server - výkon auditování výkonu a zabezpečení
Můžete zkusit tento postup k dotazu na záložní soubory protokolu a zjistit, ve kterém záložním souboru (souborech) protokolu byla/stále byla konkrétní hodnota sloupce tabulky.
Chcete-li najít uživatele, po nalezení zálohy protokolu, která naposledy existovala, můžete obnovit databázi až do zálohy protokolu a poté následovat odpověď Mark Storey-Smith .
Některé předpoklady
Zřeknutí se odpovědnosti
Toto řešení zdaleka není vodotěsné a je třeba do něj dostat mnohem více práce.
Nebyl testován ve velkém měřítku nebo dokonce v jakémkoli prostředí kromě několika malých testů. Aktuální běh byl na serveru SQL Server 2017.
Můžete použít níže procedura z Muhammad Imran , kterou jsem upravil, aby pracoval s obsahem záloh protokolu namísto obsahu protokolu živé databáze.
Tímto způsobem technicky neděláte obnovení, ale místo toho uložíte obsah protokolu do dočasné tabulky. Pravděpodobně bude stále pomalý a je velmi otevřený chybám a problémům. Ale mohlo by to fungovat teoreticky ™.
Uložená procedura používá nezdokumentovanou fn_dump_dblog
funkce pro čtení souborů protokolu.
Testovací prostředí
Zvažte tuto databázi, do které vložíme několik řádků, vezmeme 2 zálohy protokolu a na třetí zálohu zálohy odstraníme všechny řádky.
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
Postup
Uloženou proceduru můžete najít a stáhnout zde .
Nemohl jsem ho sem přidat, protože je větší než omezení počtu znaků a tuto odpověď by byl ještě méně jasný, než je.
Kromě toho byste měli být schopni spustit proceduru.
Spuštění procedury
Příklad toho, když přidám všechny své soubory protokolu (4
) do uložené procedury a spusťte proceduru hledající hodnotu1
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
To mě dostane:
ID val LogFileName
1 value1 c:\temp\Logs\log3.trn
1 value1 c:\temp\Logs\log1.trn
Kde najdeme, kdy naposledy byla operace na value1
se stalo, smazání v log3.trn
.
Několik dalších testovacích dat, přidání tabulky s různými sloupci
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
Změna názvů souborů protokolu a provedení procedury znovu
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Výsledek
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
Nový běh, hledání celého čísla (2
) v val3
sloupec dbo.WrongDeletes2
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes2',
@SearchString = '2',
@SearchColumn = 'Val3',
@LogBackupFolder ='C:\temp\Logs\'
Výsledek
Anotherval Val3 Wow LogFileName
value2 2 c c:\temp\Logs\log2.trn
value2 2 c c:\temp\Logs\log3.trn
Použití Mark Storey-Smith odpověď
Nyní víme, že se to stalo ve třetím souboru protokolu, obnovme se až do tohoto bodu:
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
Spuštění posledního dotazu v jeho odpovědi
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]
Výsledek pro mě (sysadmin)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450