慢日志中若query_time异常偏高且rows_examined远超插入行数,大概率是触发器拖慢;通过performance_schema.events_statements_history_long可定位触发器内具体慢sql,结合explain分析索引使用情况。

看慢日志里有没有 Trigger 关键字
慢日志(slow_query_log)默认不记录触发器内部语句,但 MySQL 5.7+ 会在主语句耗时远高于执行计划预期时,把触发器执行时间一并计入——只要触发器逻辑实际拖慢了 INSERT,慢日志里那条 INSERT 的 Query_time 就会异常偏高,且 Rows_examined 常远大于实际插入行数。
实操建议:
- 打开
long_query_time = 0抓全量日志,复现一次插入,直接搜TRIGGER或触发器名 - 对比同一语句在禁用触发器前后(
ALTER TABLE t DISABLE TRIGGER tr_name)的Query_time:差值基本就是触发器开销 - 注意
Rows_examined若比插入行数高几倍甚至几十倍,大概率是触发器里某条SELECT在全表扫描
查 performance_schema.events_statements_history_long
performance_schema 是唯一能直接看到触发器内 SQL 执行细节的渠道。它会把触发器里每一条独立语句(比如 INSERT INTO log_table、SELECT status FROM users)当作单独事件记录,带真实耗时、扫描行数、是否用到索引。
实操建议:
- 先启用相关消费者:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE 'events_statements_%'; - 执行一次插入后,查:
SELECT SQL_TEXT, TIMER_WAIT/1000000000 AS ms, ROWS_EXAMINED FROM performance_schema.events_statements_history_long WHERE SQL_TEXT LIKE '%log_table%' OR SQL_TEXT LIKE '%users%'; - 重点关注
TIMER_WAIT和ROWS_EXAMINED:如果某条SELECT耗时 >1ms 且ROWS_EXAMINED很大,就是瓶颈
用 SHOW PROCESSLIST 观察卡点状态
当 INSERT 变慢,SHOW PROCESSLIST 里常出现线程卡在 Updating、Sending data 或 Waiting for table metadata lock —— 这不是主语句卡住,而是触发器正在执行或等待锁。
常见现象:
- 多个线程同时卡在
Updating,且Info列显示的是触发器里写的表(如UPDATE order_summary),说明触发器更新引发了锁竞争 - 卡在
Waiting for table metadata lock,且触发器数量多(SELECT COUNT(*) FROM information_schema.TRIGGERS> 20),大概率是元数据锁争用 - 卡在
Locked状态,配合INFORMATION_SCHEMA.INNODB_TRX查持锁事务,常发现触发器里的SELECT ... FOR UPDATE正在阻塞其他插入
EXPLAIN 单独分析触发器里的每条 SQL
EXPLAIN 对主 INSERT 语句无效,但它对触发器内每一条独立 SQL 极其有用。很多“主语句很快”的假象,根源是触发器里某条 SELECT 没走索引,而你只看了主语句的执行计划。
实操建议:
- 用
SHOW CREATE TRIGGER tr_name拿出触发器定义,把里面所有SELECT、UPDATE、INSERT语句单独拎出来EXPLAIN - 重点看
type字段:出现ALL或index且rows很大,说明没走有效索引 - 如果触发器有
JOIN,确保关联字段类型完全一致(INTvsBIGINT会导致索引失效),且被驱动表上有覆盖索引
SELECT 里,也可能因为没加索引,让每次插入都触发一次全表扫描。











