SQL Serverのデータを削除したユーザーを見つける方法


29

私の上司は昨日、SQL Serverデータベースのデータを削除した人を見つける方法を尋ねる顧客からの問い合わせがありました(それが重要な場合はエクスプレス版です)。

これはトランザクションログから見つけることができると思いました(切り捨てられていなかった場合)-これは正しいですか?もしそうなら、この情報を実際にどのように見つけ出しますか?

回答:


35

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]

これは確かにSQL Expressで機能しますが、私のシステムでは、今日発生したトランザクションのみを表示します。SQL Expressにはすぐにトランザクションログが切り捨てられるとは思わなかったのですか?
マットウィルコ

5
データベースが単純な復旧モデルにある場合、非アクティブなトランザクションがログ内に留まる期間についての仮定を立てることはできません。
アーロンバートランド

3
トランザクションログはオプションではなく基本です。データベースの復旧モデル(単純または完全)とバックアップの構成(完全のみまたはログバックアップ+完全)はどのようになっていますか?
マークストーリースミス

自己結合を避けるために少しリファクタリングしましたが、ここで私の答えのためにこれを盗みましたfn_dblog。1つの欠点はUSERNAME()、はるかに便利なログイン名ではなくデータベースを返すことです。
マーティンスミス

3

データベースが完全復旧モードの場合、またはトランザクションログのバックアップがある場合は、サードパーティのログリーダーを使用してこれらの読み取りを試みることができます。

ApexSQL Log(プレミアムだが無料トライアル版)またはSQL Log Rescue(無料だがsql 2000のみ)を試すことができます


3

SQL Serverデータベースのデータを削除したユーザーを見つける方法

これは回答されましたが、SQL Serverでデフォルトのトレースが有効になっており、オブジェクトをドロップ/変更したユーザーを見つけるために使用できることを追加したいと考えていました。

オブジェクトイベント

オブジェクトイベントには、変更されたオブジェクト、作成されたオブジェクト、削除されたオブジェクトが含まれます。

注: SQL Serverには、デフォルトでそれぞれ20 MBの5つのトレースファイルがあり、これを変更する既知のサポートされた方法はありません。使用中のシステムがある場合、トレースファイルは非常に速くロールオーバーする可能性があり(数時間以内でも)、一部の変更をキャッチできない場合があります。

優れた例を見つけることができます:SQL Serverのデフォルトトレース-パフォーマンスとセキュリティ監査の力


1

この手順を試して、ログバックアップファイルを照会し、テーブルの列の特定の値がまだ/最後に存在したログバックアップファイルを見つけることができます。

ユーザーを見つけるには、どのログバックアップで値が最後に存在したかを見つけたら、そのログバックアップまでデータベースを復元し、Mark Storey-Smithの回答に従うことができます。

いくつかの前提条件

  • どの列からどの値が削除されたかを知る
  • 完全復旧モデルの下にあり、ログのバックアップを取っている
  • Ola Hallengrenのソリューションを使用する場合など、ログバックアップに日付または識別子があります

免責事項

このソリューションは防水とはほど遠いものであり、それに取り組むにはさらに多くの作業が必要です。

大規模な環境、またはいくつかの小規模なテスト以外の環境ではテストされていません。現在の実行は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)を検索val3dbo.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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.