还原触发器后写入变慢,根本原因是触发器在后续批量dml中逐行同步执行,10万行即10万次开销;应绕过触发器(如用on duplicate key update)、移出非必要逻辑或改用生成列/binlog异步处理。

还原大型触发器本身不会导致性能瓶颈——真正卡住的是后续对这张表的批量写入操作。只要表上存在触发器,INSERT、UPDATE、DELETE 就会按行触发,10 万行 = 10 万次执行,无法跳过、不能并行。
为什么还原触发器后写入突然变慢?
触发器不是“还原时执行”,而是“还原后监听”。你看到的性能暴跌,其实是业务 SQL 开始受触发器拖累:
-
SHOW PROCESSLIST中大量线程卡在Updating或Updating main table状态 - 同一条
UPDATE t SET x=1 WHERE id IN (...)在慢查询日志里反复出现,每次耗时稳定在几毫秒以上 -
INFORMATION_SCHEMA.PROFILING显示触发器逻辑占总耗时 70%+,尤其含NOW()、SELECT或函数调用时 - 即使加了索引,
UPDATE t SET y = NEW.x WHERE id = NEW.id仍慢——因为聚簇索引页分裂 + 二级索引维护开销被逐行放大
如何快速绕过已存在的触发器?
别改触发器,直接让 SQL 不走它。MySQL 没有 DISABLE TRIGGER(8.0.23+ 才支持),但有更干净的绕过路径:
- 用
INSERT ... ON DUPLICATE KEY UPDATE替代UPDATE:前提是更新依据是唯一键(主键或业务单号),数据先写临时表,再整批合并,全程不触发 - 用生成列替代时间戳字段:
updated_at DATETIME AS (NOW()) STORED(MySQL 8.0+),写入时自动计算,不经过触发器 - 审计字段如
created_by必须由应用层显式传入,禁用@session_var或触发器读连接上下文 - 统计类逻辑(如订单数累加)立刻移出 DB,改用
BINLOG解析(Canal/Maxwell)或应用层异步任务
必须保留触发器时的底线写法
如果因合规要求不能删(如金融系统审计日志),那就只允许最简化的 BEFORE 触发器,且体内严禁副作用:
- 仅支持
BEFORE INSERT和BEFORE UPDATE;禁用所有AFTER类型(AFTER极易死锁) - 体内禁止任何
SELECT、UPDATE、INSERT、DELETE - 禁止调用
READS SQL DATA或MODIFIES SQL DATA的自定义函数 - 字段赋值仅限确定性表达式,如
NEW.ts = UNIX_TIMESTAMP(),不用NOW() - 避免
IF/CASE以外的分支(循环、异常捕获)、避免嵌套子查询
最容易被忽略的一点:分批 UPDATE ... LIMIT 1000 并不能缓解触发器压力——批次越小,每行触发一次的上下文切换开销反而越重。真要分批,就该配合绕过方案(如先写临时表),而不是靠 LIMIT “假装安全”。











