MySQL触发器会显著拖慢高并发写入,因其同步执行且属于事务一部分,5ms触发器即可抬升行锁平均时间、降低TPS;跨表操作、远程调用、同表写入易引发锁争用或死锁;空触发器也有0.1–0.3ms固定开销。

触发器会显著拖慢高并发写入场景
MySQL 触发器在 INSERT、UPDATE、DELETE 执行期间同步运行,属于事务的一部分。这意味着:只要触发器逻辑没跑完,该行(甚至整个表,取决于隔离级别和锁策略)就无法被其他事务安全修改。在每秒数百次以上写入的业务中(如订单创建、日志上报),一个耗时 5ms 的触发器就能让 innodb_row_lock_time_avg 明显升高,进而拉低整体 TPS。
触发器里的 SELECT 或远程调用是并发杀手
以下操作在触发器中尤其危险:
- 在
BEFORE INSERT里执行SELECT ... FROM other_table WHERE x = NEW.y—— 可能引发间隙锁或锁升级,阻塞其他插入 - 调用
SLEEP()、UUID()(部分版本)、或自定义函数(含外部 HTTP 请求)—— 直接延长事务持有时间 - 对同一张表做
INSERT/UPDATE(比如自增统计表)—— 极易触发Deadlock found when trying to get lock
DELIMITER $$ CREATE TRIGGER order_after_insert_log AFTER INSERT ON orders FOR EACH ROW BEGIN -- ❌ 危险:跨表 UPDATE + 可能锁住 users 表的某一行 UPDATE users SET last_order_time = NOW() WHERE id = NEW.user_id; END$$ DELIMITER ;
替代方案比优化触发器更有效
多数“必须用触发器”的需求,其实有更低开销的选择:
- 把计数、状态更新等逻辑移到应用层,在主事务提交后异步处理(例如发 MQ 消息)
- 用
INSERT ... ON DUPLICATE KEY UPDATE替代BEFORE INSERT中的查重逻辑 - 对审计类日志,改用
BINLOG解析(如 Canal / Debezium),完全绕过事务链路 - 真需要强一致性且逻辑简单?优先考虑生成列(
GENERATED COLUMN)或检查约束(CHECK CONSTRAINT)
监控触发器真实开销不能只看 slow log
slow_query_log 默认不记录触发器内部语句,容易误判。要定位瓶颈,必须开启:
-
performance_schema=ON+ 启用events_statements_history_long - 查
performance_schema.events_statements_history_long中EVENT_NAME包含trigger的记录 - 重点关注
LOCK_TIME和EXECUTION_ENGINE(InnoDB vs MyISAM 行为差异大)
一个常被忽略的事实:即使触发器体为空,每次触发仍带来约 0.1–0.3ms 的固定上下文切换开销。在 QPS 超 2000 的写入集群里,这已足够让 p99 延迟跳变。











