不能用truncate或delete全表清理审计日志表,因其会锁表、无法回滚、引发全表扫描和长事务,拖慢业务并破坏主从一致性;应分批删除、加索引、限行数。

触发器本身不产生日志,真正要清理的是它写入的审计日志表——比如 audit_log 或 user_operation_log。直接删表或 truncate 会阻塞业务,还可能破坏主从一致性。
为什么不能用 TRUNCATE 或 DELETE 全表清理
触发器写入的日志表通常高频插入、有大量历史数据,但业务查询常按时间范围(如最近7天)或操作人过滤。全表清理风险极高:
-
TRUNCATE TABLE audit_log是 DDL 操作,会锁整个表,且无法回滚,主从延迟可能飙升 - 无 WHERE 的
DELETE FROM audit_log在未加索引字段上执行,极易触发全表扫描 + 长事务,撑爆undo log - 如果日志表和业务库共用磁盘阵列,IO 压力会直接拖慢线上交易
安全清理日志表的三步法
核心是“分批、异步、可监控”,避免影响主流程:
- 先确认
operate_time字段有 B-tree 索引:CREATE INDEX idx_operate_time ON audit_log (operate_time); - 用小批量删除代替全量:每次只删 1000 行,加
LIMIT 1000和明确WHERE条件,例如:DELETE FROM audit_log WHERE operate_time - 写成循环脚本(Shell/Python),每次执行后
SLEEP 0.1秒,再查剩余行数,直到ROW_COUNT() = 0;同时记录每次执行耗时与影响行数,便于事后分析
更可持续的方案:分区表 + 定期 DROP PARTITION
如果日志表已按月分区(如 audit_log_202507),清理就变成毫秒级操作,且不走事务日志:
- 建表时就按
operate_time分区:PARTITION BY RANGE (TO_DAYS(operate_time)) - 清理旧数据只需:
ALTER TABLE audit_log DROP PARTITION p_202412; - 注意:MySQL 8.0+ 支持
EXCHANGE PARTITION归档,可把老分区数据快速移到归档库,比 INSERT + DELETE 快一个数量级
最容易被忽略的是:日志表清理后,必须立刻执行 ANALYZE TABLE audit_log 更新统计信息,否则后续查询可能因优化器误判而走错执行计划——尤其当刚删掉 90% 数据时。










