
SQL 触发器是实现数据库操作日志审计最直接、低侵入的方式之一,但容易因设计不当导致性能下降或日志缺失。关键在于:触发器要轻量、日志表要独立、关键字段要完整、错误处理要兜底。
触发器日志表设计要点
日志表不能和业务表共用同一库或同一磁盘阵列,避免写日志拖慢主业务。建议单独建库(如 audit_db),表结构至少包含以下字段:
- log_id:自增主键,便于分页与归档
- table_name、operation_type(INSERT/UPDATE/DELETE):标识操作来源与类型
- old_data 和 new_data:用 JSON 或 TEXT 类型存储变更前后的关键字段(非全字段),避免大字段膨胀
-
operated_by:优先从
CURRENT_USER()或应用层传入的 session 变量获取,不依赖客户端 IP -
operate_time:用
NOW(3)记录毫秒级时间,便于排查时序问题 - client_ip 和 app_trace_id(可选):配合应用日志快速定位请求链路
触发器编写避坑指南
一个表对应一套 INSERT/UPDATE/DELETE 触发器,不合并;每个触发器只做一件事:写日志。常见错误需规避:
- 不在触发器中调用存储过程或远程服务——会阻塞事务,超时即失败
- 不使用
SELECT ... INTO查询业务表——可能引发死锁或读到未提交数据 - UPDATE 触发器中慎用
OLD.*和NEW.*全字段拼接——应只取业务关心的字段,如NEW.user_id, NEW.status, OLD.status - 必须用
BEGIN...END包裹,并添加DECLARE CONTINUE HANDLER捕获 SQL 异常,防止日志失败导致主操作回滚
敏感操作专项审计策略
对 DROP TABLE、TRUNCATE、权限变更等高危操作,仅靠 DML 触发器无法捕获。需组合使用:
- MySQL 开启 general_log 并过滤关键词(如 'DROP', 'GRANT'),但仅限短期调试——开启后 I/O 压力显著上升
- PostgreSQL 启用 pg_audit 扩展,配置
audit_table和audit_role实现细粒度 DDL 审计 - SQL Server 利用 DDL 触发器 +
EVENTDATA()函数捕获 schema 变更,并写入专用审计表 - 所有 DDL 审计日志必须异步落盘(如写入消息队列再消费),禁止同步阻塞主流程
日志归档与可用性保障
审计日志不是“写了就完”,需可持续运维:
- 按月分区日志表(如
audit_log_202409),用ALTER TABLE ... DROP PARTITION快速清理过期数据 - 每日凌晨执行校验脚本:比对当日业务表变更行数与日志表插入行数,偏差 > 0.5% 即告警
- 日志表加
INDEX (table_name, operate_time),避免全表扫描查询;对operated_by高频查询字段也建索引 - 备份策略独立于业务库:日志库每日全备 + binlog 增量,保留至少 180 天,满足等保 2.0 要求
不复杂但容易忽略:上线前务必在压测环境模拟峰值写入,观察触发器平均延迟是否稳定在 1ms 内;任何超过 5ms 的触发器都应重构或改用应用层日志补位。










