触发器执行是否走索引直接影响I/O放大倍数:未建索引会导致全表扫描,隐式类型转换使索引失效,嵌套调用加剧回表I/O,且触发器SQL参与redo与binlog双重刷盘,显著增加写放大。

触发器执行是否走索引,直接影响I/O放大倍数
MySQL触发器本身不产生I/O,但它执行的SQL语句会。最常见陷阱是:触发器里写了UPDATE t2 SET status = 'processed' WHERE order_id = NEW.id,而t2.order_id没建索引。这时每次INSERT都会触发一次全表扫描——10万次插入就等于10万次全表扫描,I/O直接爆炸。
实操建议:
- 对触发器中所有
WHERE、JOIN、ORDER BY字段,用EXPLAIN验证执行计划,确保type不是ALL - 特别注意隐式类型转换:比如
order_id是BIGINT,但触发器里写成WHERE order_id = '123',索引会失效 - 用
SHOW PROFILES或performance_schema.events_statements_history抓取触发器内嵌SQL的实际执行耗时与rows_examined
触发器调用链导致的多层回表I/O叠加
一个触发器调用另一个存储过程,过程中又更新第三张表——这种嵌套会让I/O成本非线性增长。比如主表插入触发A表更新(走二级索引+回表),A表更新又触发B表插入(再走一次二级索引+回表),两次回表就是两轮随机I/O,SSD上延迟可能从0.1ms飙到0.8ms以上。
关键判断点:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 检查
INFORMATION_SCHEMA.TRIGGERS确认是否有跨表级联触发 - 在
performance_schema.setup_consumers中开启events_statements_nested,观察嵌套深度 - 用
OPTIMIZER_TRACE打开后执行带触发器的INSERT,看trace里join_execution部分是否出现多次table扫描
触发器写binlog与redo log的双重刷盘开销
触发器内SQL默认参与事务,意味着它产生的变更会写入redo log(受innodb_flush_log_at_trx_commit控制)和binlog(受sync_binlog控制)。如果这两个参数都是1,单条INSERT触发的刷盘次数可能翻倍——尤其当触发器执行的是INSERT ... SELECT这类批量操作时。
真实影响场景:
- OLTP系统中高频小事务(如订单创建)配触发器,容易成为I/O瓶颈点
- 使用ROW格式binlog时,触发器生成的每一行变更都会被完整记录,日志体积膨胀快
-
innodb_doublewrite=ON下,触发器引发的额外页写入也会被doublewrite buffer捕获,进一步增加写放大
如何用监控定位触发器的真实I/O代价
不要只看SHOW PROCESSLIST里的触发器SQL,它不体现底层I/O。真正有效的方式是结合引擎层指标交叉验证:
- 查
SHOW ENGINE INNODB STATUS\G里的LOG段,对比触发器启用前后Log sequence number增长速率 - 监控
Performance Schema中的events_waits_summary_global_by_event_name,过滤wait/io/file/innodb/innodb_data_file和wait/io/file/innodb/innodb_log_file等待事件 - 用
pt-ioprofile在系统层面抓取触发器活跃时段的磁盘IO分布,确认是否集中在ibdata1或ib_logfile
最容易被忽略的是:触发器引发的临时表溢出。比如触发器里GROUP BY没加索引,tmp_table_size又设得太小,Created_tmp_disk_tables飙升,这种顺序I/O爆发比随机回表更伤IO吞吐。

















