触发器不影响主SQL执行计划,EXPLAIN结果仅反映主语句本身;其性能开销真实存在但不可见,需通过performance_schema或单独EXPLAIN触发器内SQL排查优化。

触发器修改不触发主SQL执行计划重编译
改了触发器,EXPLAIN出来的执行计划还是老样子——这不是缓存没清,而是MySQL压根就不把触发器逻辑纳入执行计划生成范围。触发器是语句执行完成(或回滚前)才被调用的“事后动作”,优化器在解析阶段根本看不到它,自然不会因触发器变更而重新计算访问路径、索引选择或JOIN顺序。
执行计划不刷新,但实际性能可能已崩
你看到EXPLAIN显示“Using index”,执行却卡住2秒,真凶往往藏在刚改过的触发器里。比如:
- 新加的
AFTER INSERT里写了UPDATE stats SET cnt = cnt + 1 WHERE type = NEW.type,但stats(type)没索引 → 每插一行就全表扫一次 - 把原本直接赋值的
SET NEW.status = 'active'换成调用CALL get_status_by_rule(NEW.user_id)→ 每次都重解析+权限校验+隐式转换 - 触发器里加了
JSON_EXTRACT(NEW.payload, '$.tags')→ 字段越大解析越慢,且无法走索引
怎么确认是新触发器拖慢了?
别信EXPLAIN,得抓真实耗时链路:
- 查
performance_schema.events_statements_history_long,过滤EVENT_NAME LIKE '%trigger%',看触发器内SQL的实际执行时间 - 临时禁用:用
RENAME TABLE t TO t_off隔离验证(注意应用层同步切表),对比QPS和P99延迟变化 - 对触发器里的每条SQL单独跑
EXPLAIN,重点盯type字段是否为ALL或index,以及key列是否为空 - 检查
SHOW ENGINE INNODB STATUS里的trx_query,如果锁等待堆栈指向的是主语句,但LOCK WAIT源头在触发器DML上,就是它了
真正要刷新的不是执行计划,而是触发器内部的SQL
主SQL执行计划不会变,但触发器本身的效率完全取决于它内部写的每一条语句。最容易被忽略的是:
-
WHERE条件里用了函数(如DATE(created_at))→ 索引彻底失效 - 字段类型不一致(
user_id INTvsNEW.user_id BIGINT)→ 隐式转换导致全表扫描 - 没声明
DETERMINISTIC的存储过程调用 → 每次都重生成执行计划 - 触发器里查的表刚加了新字段,但统计信息没更新 →
optimizer_switch误判行数,选错索引
改完触发器后,最该做的不是FLUSH TABLES,而是进performance_schema捞出那几条子语句,逐个EXPLAIN,再看SHOW INDEX FROM xxx核对索引覆盖是否完整。










