找出誰刪除了某個表


當實例沒有做DDL Trigger和其它一些監控時,如何知道誰刪除了某個表?通過系統函數fn_dblog,fn_dump_dblog和默認跟蹤可以找到。

1. 創建測試環境:新建個表,插入一條數據,然后drop掉

CREATE DATABASE test
go
USE test
go
CREATE TABLE dbo.fnlog_test
(id INT IDENTITY ,val VARCHAR(10) DEFAULT 'x')
GO
CREATE CLUSTERED INDEX IX_ft_id
ON dbo.fnlog_test (ID)

GO
INSERT INTO dbo.fnlog_test
VALUES (DEFAULT )
GO
DROP TABLE fnlog_test
GO

2. 通過sys.fn_dblog,找出相關信息:

USE test
go
SELECT [Transaction ID],[Transaction Name],[Begin Time],[Server UID],SPID
FROM sys.fn_dblog(NULL,null)
WHERE [Transaction Name]='DROPOBJ'
go

image

 

3. 上一步中這里得到了事務ID,開始時間,Suid,SPID等,但是執行刪除的SPID可以已經logout或者被重用了。所以要找出“當時”的這個SPID。

先根據事務ID,找出被刪除的對象吧。查詢結果的“OBJECT: 9:245575913:0”,9是DB_ID,245575913是object_id,就是被刪除的表的object_id.

SELECT TOP(1) [Lock Information]
FROM sys.fn_dblog(NULL,NULL)
WHERE [Lock Information] LIKE '%SCH_M OBJECT%' AND [Transaction ID]='0000:000002e7'
go

image

4. 通常SQL Server實例安裝后會開啟一個默認跟蹤(Default Trace),這個跟蹤會記錄一引起級別較高的重要信息。先找到默認跟蹤

SELECT id,status,path FROM sys.traces
WHERE is_default=1

image

5. 根據前幾步中得到的trace path,事務ID,開始時間,SPID,object_id,通過默認跟蹤得到進一步的信息:

SELECT DatabaseID,NTUserName,HostName,ApplicationName,LoginName,
SPID,ObjectID,StartTime, EventClass,EventSubClass
FROM sys.fn_trace_gettable('D:\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Log\log_10.trc',1)
WHERE SPID=52 AND  StartTime>'2013/07/15 11:32:44:133' AND ObjectID =245575913
GO
image

這一步中就得到了誰刪除了這個表的更具體信息了。需要說明一下的是EventClass=47,EventSubclass=(0,1),這記錄了跟蹤事件的操作。

SELECT te.trace_event_id,te.name,tsv.subclass_value,tsv.subclass_name
FROM sys.trace_events te
INNER JOIN sys.trace_subclass_values tsv
ON te.trace_event_id=tsv.trace_event_id 
WHERE te.trace_event_id=47 AND tsv.subclass_value IN(0,1)

image

6. 如果是生產環境的,事務日志可能被截斷而被重用覆蓋了。這里就需要從日志備份中讀取日志信息來定位。需要用到fn_dump_dblog.

  重新構建測試環境:

CREATE DATABASE test
go
USE test
go
CREATE TABLE dbo.fnlog_test
(id INT IDENTITY ,val VARCHAR(10) DEFAULT 'x')
GO
CREATE CLUSTERED INDEX IX_ft_id
ON dbo.fnlog_test (ID)

GO
INSERT INTO dbo.fnlog_test
VALUES (DEFAULT )
GO
USE master
go
BACKUP DATABASE test
TO DISK='D:\SQLSample\test.bak'
WITH init
go
USE test
go
DROP TABLE fnlog_test
GO
USE master
go
BACKUP LOG test
TO DISK='D:\SQLSample\test.bck'
WITH init
go
2. 和3. 的查詢要換成fn_dump_dblog,其它的步驟是一樣的。這里我另外做的測試,所以事務ID與前面不同了。

SELECT 
[Transaction ID],[Transaction Name],[Begin Time],[Server UID],SPID 
FROM fn_dump_dblog (NULL, NULL, N'DISK', 1, N'D:\SQLSample\test.bck', 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT) 
WHERE [Transaction Name] LIKE '%DROPOBJ%'

SELECT TOP(1) [Lock Information]
FROM fn_dump_dblog (NULL, NULL, N'DISK', 1, N'D:\SQLSample\test.bck', 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 
 DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT) 
WHERE [Lock Information] LIKE '%SCH_M OBJECT%' AND [Transaction ID]='0000:000002b8'

總結:

  1. 在SQL Server 2008 R2 SP2&SQL Server 2012 SP1測試通過

  2. trace文件是rollover的,所以要找對path,同樣要從日志備份中查詢的話,也要找對日志備份文件的時間

  3. fn_dblog和fn_dump_dblog是Undocumented Function.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM