回答:
Expressでfn_dblogを試したことはありませんが、fn_dblogが利用可能な場合は、次の操作で削除操作ができます。
SELECT
*
FROM
fn_dblog(NULL, NULL)
WHERE
Operation = 'LOP_DELETE_ROWS'
関心のあるトランザクションのトランザクションIDを取得し、トランザクションを開始したSIDを特定します。
SELECT
[Transaction SID]
FROM
fn_dblog(NULL, NULL)
WHERE
[Transaction ID] = @TranID
AND
[Operation] = 'LOP_BEGIN_XACT'
次に、SIDからユーザーを識別します。
SELECT
*
FROM
sysusers
WHERE
[sid] = @SID
編集:指定したテーブルの削除を見つけるためにそれらすべてをまとめます:
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]
fn_dblog
。1つの欠点はUSERNAME()
、はるかに便利なログイン名ではなくデータベースを返すことです。
データベースが完全復旧モードの場合、またはトランザクションログのバックアップがある場合は、サードパーティのログリーダーを使用してこれらの読み取りを試みることができます。
ApexSQL Log(プレミアムだが無料トライアル版)またはSQL Log Rescue(無料だがsql 2000のみ)を試すことができます。
SQL Serverデータベースのデータを削除したユーザーを見つける方法
これは回答されましたが、SQL Serverでデフォルトのトレースが有効になっており、オブジェクトをドロップ/変更したユーザーを見つけるために使用できることを追加したいと考えていました。
オブジェクトイベント
オブジェクトイベントには、変更されたオブジェクト、作成されたオブジェクト、削除されたオブジェクトが含まれます。
注: SQL Serverには、デフォルトでそれぞれ20 MBの5つのトレースファイルがあり、これを変更する既知のサポートされた方法はありません。使用中のシステムがある場合、トレースファイルは非常に速くロールオーバーする可能性があり(数時間以内でも)、一部の変更をキャッチできない場合があります。
優れた例を見つけることができます:SQL Serverのデフォルトトレース-パフォーマンスとセキュリティ監査の力
この手順を試して、ログバックアップファイルを照会し、テーブルの列の特定の値がまだ/最後に存在したログバックアップファイルを見つけることができます。
ユーザーを見つけるには、どのログバックアップで値が最後に存在したかを見つけたら、そのログバックアップまでデータベースを復元し、Mark Storey-Smithの回答に従うことができます。
いくつかの前提条件
免責事項
このソリューションは防水とはほど遠いものであり、それに取り組むにはさらに多くの作業が必要です。
大規模な環境、またはいくつかの小規模なテスト以外の環境ではテストされていません。現在の実行はSQL Server 2017で行われました。
ライブデータベースのログの内容ではなく、ログバックアップの内容を操作するように変更したMuhammad Imranの以下の手順を使用できます。
この方法では、技術的には復元を実行せず、代わりにログの内容を一時テーブルにダンプします。おそらくまだ遅いでしょうし、バグや問題に対して非常にオープンです。しかし、理論的には機能します™。
ストアドプロシージャは、文書化されていないfn_dump_dblog
関数を使用してログファイルを読み取ります。
テスト環境
いくつかの行を挿入し、2つのログバックアップを取得し、3番目のログバックアップですべての行を削除するこのデータベースを検討します。
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
手順
ストアドプロシージャはこちらで検索およびダウンロードできます。
文字の制限よりも大きいため、ここに追加することはできませんでした。また、この答えはそれよりもさらに明確ではありません。
これとは別に、プロシージャを実行できるはずです。
プロシージャを実行する
この例では、すべてのログファイル(4
)をストアドプロシージャに追加し、value1を探してプロシージャを実行します。
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
これは私を取得します:
ID val LogFileName
1 value1 c:\temp\Logs\log3.trn
1 value1 c:\temp\Logs\log1.trn
最後に操作が行われvalue1
たときに見つけることができる場所は、の削除ですlog3.trn
。
いくつかのテストデータ、異なる列を持つテーブルを追加
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
ログファイル名の変更と手順の再実行
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
結果
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
新しい実行、列の整数(2
)を検索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\'
結果
Anotherval Val3 Wow LogFileName
value2 2 c c:\temp\Logs\log2.trn
value2 2 c c:\temp\Logs\log3.trn
Mark Storey-Smithの回答を適用する
3番目のログファイルで発生したことがわかったので、その時点まで復元しましょう。
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
彼の答えの最後のクエリを実行する
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]
私のための結果(sysadmin)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450