触发器使批量sql退化为o(n)串行执行,每行触发一次且无法优化;空触发器也有0.1–0.3ms开销,10万行即10–30秒等待;含now()/uuid()等函数时高并发下延迟可达2ms+;load data infile同样逐行触发;触发器内未走索引的select会导致每行全表扫描;锁范围被悄悄放大且无法监控;真正绕过方式只有insert ... on duplicate key update、insert ... select+临时表、生成列及应用层传参。

大规模 SQL 写入中频繁使用触发器,会直接把 O(1) 的批量操作退化成 O(n) 甚至 O(n²) 的串行执行链——不是“可能慢”,而是每多一行数据,就多一次不可跳过的同步开销。
触发器在 INSERT INTO ... VALUES (), () 中逐行执行
MySQL 不会对多值 INSERT 做批量触发优化。哪怕语句写成 INSERT INTO orders VALUES (1,'a'),(2,'b'),(3,'c'),也会为每一行分别调用一次触发器逻辑。
- 空触发器也有 0.1–0.3ms 固定解析与上下文切换开销;10 万行就是额外 10–30 秒纯等待
- 触发器里含
NOW()、UUID()等函数时,高并发下系统时钟/随机数生成器争用明显,单次延迟可飙到 2ms+ -
LOAD DATA INFILE同样逃不掉逐行触发,索引优化、buffer pool 预热全失效
触发器内 SELECT 没走索引 = 每写一行就扫一次全表
常见陷阱是:在 AFTER INSERT 里写 SELECT COUNT(*) FROM logs WHERE user_id = NEW.user_id,看起来只查一行,但若 logs(user_id) 缺失索引、类型不匹配(如 BIGINT vs INT),或 WHERE 用了函数(如 DATE(created_at)),EXPLAIN 就会显示 type: ALL。
一款AI工具,主要用于在主代理响应前,并行运行Kimi K2.5和GPT 5.3 Codex,注入双方观点以增强认知多样性,适合需要提升相关任务效率的用户。
- 这种 SQL 单独执行一次是问题,放进触发器里就是灾难:每插入一行都触发一次全表扫描
- 必须单独把触发器里的
SELECT拎出来跑EXPLAIN,不能只看主语句的执行计划 -
SHOW INDEX FROM logs看不到隐式转换导致的索引失效,得人工核对字段类型和表达式写法
锁范围被触发器悄悄放大且无法监控
触发器和主 SQL 共享同一事务上下文,它里面任何一句 UPDATE 或 SELECT ... FOR UPDATE,都会把锁持有时间延长、锁范围扩大——而这些动作不会出现在慢查询日志里,EXPLAIN 也完全不展示。
- 主语句只锁
orders.id = 123,触发器却去更新stats表;若stats(type)没索引,就会升级成表级锁,且持续到整个事务提交 -
SHOW ENGINE INNODB STATUS显示LOCK WAIT,但trx_query只显示主 SQL,阻塞源藏在触发器里 -
innodb_row_lock_time_avg突增,slow_query_log却找不到对应慢 SQL——因为触发器耗时不单独记录
真正绕过触发器的写法只有这几种
别花时间给触发器加索引或拆函数,设计定位本就不支持批量。能绕开就绕开,而不是优化一个不该承担该职责的机制。
-
INSERT ... ON DUPLICATE KEY UPDATE:不显式触发UPDATE,就不会进触发器路径 -
INSERT ... SELECT+ 临时表 JOIN:整批计算完再插入,天然跳过逐行触发 - 字段自动填充改用生成列:
updated_at DATETIME AS (NOW()) STORED(MySQL 8.0+) - 审计字段(如
created_by)必须由应用层显式传参,不要依赖@session_var或触发器读连接上下文
最麻烦的不是触发器慢,而是你连它在哪慢都看不见;最危险的不是它做了什么,而是它做了什么你根本不知道——比如某张表有 37 个触发器,其中 2 个已失效、1 个在 quietly 覆盖字段值,而所有这些,都不会出现在任何一条应用日志或监控告警里。










