多人共用資料庫 (DBA、開發、運維) 時,未經管控的 DDL 操作 (建表、改 SP、刪索引) 極易造成混亂與事故。本文實作基於 DDL Trigger + EVENTDATA() 的自動稽核系統,記錄變更細節並即時郵件通知。
msdb.dbo.DatabaseLog:集中儲存所有資料庫的 DDL 事件DDL_DATABASE_LEVEL_EVENTS,解析 XML 事件資料寫入稽核表並發信USE msdb;
GO
CREATE TABLE dbo.DatabaseLog
(
DatabaseLogID INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
PostTime DATETIME NOT NULL,
DatabaseUser sysname NOT NULL,
LoginName sysname NULL,
ClientHost sysname NULL,
EventType sysname NOT NULL, -- CREATE_TABLE, ALTER_PROCEDURE...
SchemaName sysname NULL,
ObjectName sysname NULL,
TSQLCommand NVARCHAR(MAX) NOT NULL,
XmlEvent XML NOT NULL
);
GO
USE MyAssistant;
GO
CREATE TRIGGER DTG_DatabaseDdlTriggerLog
ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
BEGIN
SET NOCOUNT ON;
DECLARE @data XML = EVENTDATA();
DECLARE @eventType sysname = @data.value('(/EVENT_INSTANCE/EventType)[1]', 'sysname');
DECLARE @schema sysname = @data.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname');
DECLARE @object sysname = @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname');
DECLARE @tsql NVARCHAR(MAX) = @data.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'NVARCHAR(MAX)');
DECLARE @loginName NVARCHAR(MAX) = @data.value('(/EVENT_INSTANCE/LoginName)[1]', 'NVARCHAR(MAX)');
-- 寫入稽核表
INSERT INTO msdb.dbo.DatabaseLog
(PostTime, DatabaseUser, LoginName, ClientHost, EventType, SchemaName, ObjectName, TSQLCommand, XmlEvent)
VALUES
(GETDATE(), CURRENT_USER, @loginName, HOST_NAME(), @eventType, @schema, @object, @tsql, @data);
-- 組裝 HTML 郵件內容 (僅含最新一筆)
DECLARE @tableHTML NVARCHAR(MAX) =
N'DDL Event Alert
' +
N'' +
N'Time DB User Login Client Event Schema Object TSQL ' +
CAST((
SELECT
td = CONVERT(VARCHAR(23), PostTime, 121), '',
td = DatabaseUser, '',
td = LoginName, '',
td = ClientHost, '',
td = EventType, '',
td = SchemaName, '',
td = ObjectName, '',
td = TSQLCommand, ''
FROM msdb.dbo.DatabaseLog
WHERE DatabaseLogID = (SELECT MAX(DatabaseLogID) FROM msdb.dbo.DatabaseLog)
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX)) +
N'
';
-- 發送郵件 (需預先設定 Database Mail Profile)
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'DataBase_DDL_Event', -- 郵件設定檔名稱
@recipients = 'dba-team@company.com', -- 收件人
@subject = 'DDL Event - Database: MyAssistant',
@body = @tableHTML,
@body_format = 'HTML';
END;
GO
DROP TABLE TestTable; 或 ALTER PROCEDURE usp_Test ...SELECT TOP 10 * FROM msdb.dbo.DatabaseLog ORDER BY PostTime DESC;

| 資訊 | XPath | 範例值 |
|---|---|---|
| 事件類型 | /EVENT_INSTANCE/EventType | CREATE_TABLE, ALTER_PROCEDURE, DROP_INDEX |
| 結構描述 | /EVENT_INSTANCE/SchemaName | dbo |
| 物件名稱 | /EVENT_INSTANCE/ObjectName | Customers |
| 物件類型 | /EVENT_INSTANCE/ObjectType | TABLE, PROCEDURE, INDEX |
| TSQL 命令文本 | /EVENT_INSTANCE/TSQLCommand/CommandText | CREATE TABLE... |
| 登入名稱 | /EVENT_INSTANCE/LoginName | DOMAIN\dev_user |
| 資料庫名稱 | /EVENT_INSTANCE/DatabaseName | MyAssistant |
| SPID | /EVENT_INSTANCE/SPID | 52 |
| 事件時間 | /EVENT_INSTANCE/PostTime | 2024-01-15T10:30:45.123 |
ON ALL SERVER FOR DDL_SERVER_LEVEL_EVENTS 監控 CREATE DATABASE, ALTER LOGIN 等實例級事件UPDATE STATISTICS, CREATE STATISTICS 等高頻自動事件Service Broker 隊列,由獨立啟動程序發信,避免郵件發送失敗阻塞 DDLdb_owner / 稽核角色讀取,防竄改TRY...CATCH 吞掉)DISABLE TRIGGER DTG_DatabaseDdlTriggerLog ON DATABASE;msdb 需確保 Trigger 擁有者有 msdb 寫入權限 (通常 dbo 擁有者即可)