sql server 必须使用数据库级 ddl 触发器(如 on database for create_table)监控结构变更,不能用 dml 触发器;需过滤 tempdb、避免阻塞操作,并通过 eventdata() 写入日志表。

不能靠普通 DML 触发器(AFTER INSERT、BEFORE UPDATE)捕获 CREATE TABLE 或 ALTER TABLE ——它们对 DDL 语句完全无效,监控必然漏掉。
SQL Server 必须用 ON DATABASE FOR CREATE_TABLE, ALTER_TABLE, DROP_TABLE
DDL 触发器只能建在数据库级别,且语法必须是 FOR,不是 AFTER 或 INSTEAD OF(后者在 DDL 场景下非法)。常见错误包括:
- 写成
ON TABLE:表级触发器只响应 DML,对结构变更无感知 - 在触发器里调用
sp_send_dbmail或xp_cmdshell:会阻塞整个 DDL 事务,导致ALTER TABLE卡死数分钟甚至更久 - 忽略
tempdb过滤:所有临时对象变更都会触发,日志爆炸且无业务价值,应在开头加IF EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]', 'sysname') = 'tempdb' RETURN
正确做法是提取 EVENTDATA() 中的 XML,写入本地日志表(如 ddl_change_log),字段至少含:DatabaseName、ObjectName、EventType、TSQLCommand。
PostgreSQL 只能用 event trigger + NOTIFY
PG 没有传统 DDL 触发器,log_statement = 'ddl' 只存原始语句文本,无法解析出对象类型或 schema,审计不可靠。必须走 CREATE EVENT TRIGGER 配合 pg_event_trigger_ddl_commands():
-
CREATE EVENT TRIGGER必须由超级用户执行,且不能在事务块中运行(否则报错ERROR: cannot create event trigger within transaction block) - 监听
ddl_command_end事件才能拿到完整对象信息;sql_drop要单独监听,用pg_event_trigger_dropped_objects()提取被删对象 -
NOTIFYpayload 限制 8000 字节:别传完整COMMENT ON COLUMN,只传object_identity和command_tag(如'CREATE TABLE') - 客户端必须长连接执行
LISTEN schema_changes,断连即丢事件;生产环境务必配序号表或 WAL 位置跟踪断点
Oracle DDL 触发器必须拆成 BEFORE DROP 和 AFTER ALTER 两个
Oracle 不支持单个触发器覆盖多种 DDL 类型。比如想同时阻止 DROP TABLE 并记录 ALTER TABLE,必须分别建两个触发器:
-
BEFORE DROP可用RAISE_APPLICATION_ERROR中止操作;AFTER ALTER只能记日志,无法回滚 - 禁止在同一个触发器里写
IF ora_sysevent = 'DROP' THEN ... ELSIF ora_sysevent = 'ALTER' THEN ...:一旦RAISE_APPLICATION_ERROR在 ALTER 分支执行,会意外中断合法的 ALTER - 上下文变量只认
ora_dict_obj_owner和ora_dict_obj_name,不要查USER_TABLES——触发时表可能已部分删除,查不到反而放行 - 日志写入必须用
SYSDATE,CURRENT_DATE受会话时区影响,归档分析时时间错乱
MySQL 5.7+ 唯一可行方案是轮询 performance_schema.events_statements_history
MySQL 原生无 DDL 触发器,binlog 在 ROW 格式下根本不记录 CREATE/ALTER,解析这条路走不通。唯一轻量方案是启用并轮询 performance_schema:
- 先开启:执行
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history' - 该表默认只保留最近 10000 条,且
sql_text可能被截断,需结合digest_text和event_name判断是否为 DDL - 权限要求低,但需注意:表内容易被覆盖,轮询间隔不能太长;高并发下仍可能漏掉短命语句
- 不适用于严格审计场景,仅适合内部变更通知或低频同步
跨数据库统一监控最难的不是语法差异,而是“阻塞”和“丢失”的权衡:SQL Server 和 Oracle 的 DDL 触发器介入事务,安全但怕写重逻辑;PostgreSQL 的 event trigger 异步解耦,可靠但要自己管断连;MySQL 索性放弃实时,靠轮询换稳定——选哪个,取决于你敢不敢让 ALTER TABLE 多等那几毫秒。











