私の上司は昨日、顧客から、SQL Serverデータベースのデータを削除したユーザーを確認する方法について質問を受けました(重要な場合はExpress Editionです)。
これはトランザクションログから見つけることができると思いました(切り捨てられていなかった場合)-これは正しいですか?もしそうなら、実際にどのようにしてこの情報を見つけ出すのですか?
私はExpressで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]
データベースが完全復旧モードの場合、またはトランザクションログのバックアップがある場合は、サードパーティのログリーダーを使用してこれらを読み取ってみることができます。
ApexSQL Log (プレミアムだが無料トライアルあり)または SQL Log Rescue (無料だがSQL 2000のみ)を試すことができる。
sQL Serverデータベースで一部のデータを削除したユーザーを見つける方法
これは回答されていますが、SQL Serverではデフォルトのトレースが有効になっており、オブジェクトをドロップ/変更したユーザーを見つけるために使用できることを追加したいと考えています。
オブジェクトイベント
オブジェクトイベントには、オブジェクト変更、オブジェクト作成、オブジェクト削除が含まれます。
注:SQL Serverにはデフォルトで5つのトレースファイルがあり、それぞれ20 MBあります。これを変更するためのサポートされている既知の方法はありません。システムがビジーな場合、トレースファイルのロールオーバーが非常に速く(数時間以内であっても)、一部の変更をキャッチできない可能性があります。
優れた例を見つけることができます: SQL Serverの既定のトレース-パフォーマンスとセキュリティ監査の力
この手順を実行してログバックアップファイルにクエリを実行し、テーブルの列の特定の値がまだ/最後に存在していたログバックアップファイルを見つけることができます。
ユーザーを見つけるには、どのログバックアップで値が最後に存在したかを見つけた後、そのログバックアップまでデータベースを復元し、 Mark Storey-Smith の回答に従います。
いくつかの前提条件
免責事項
このソリューションは防水性には程遠いため、さらに多くの作業が必要になります。
大規模な環境、またはいくつかの小規模なテスト以外の環境ではテストされていません。現在の実行はSQL Server 2017でした。
以下を使用できます 手順 from Muhammad Imranlog backupsライブデータベースのログの内容の代わりに。
この方法では、技術的には復元を行わず、代わりにログの内容を一時テーブルにダンプします。それはおそらく遅いでしょう、そしてバグと問題に非常にオープンです。しかし、理論的にはそれは機能します。
ストアドプロシージャは、文書化されていない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
手順
ストアドプロシージャ here を見つけてダウンロードできます。
文字数制限よりも大きいため、ここに追加することはできません。この答えは、それよりも明確ではなくなります。
これとは別に、プロシージャを実行できるはずです。
プロシージャの実行
この例では、すべてのログファイル(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
Applying 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