事务提交慢八成是磁盘io卡在fsync上,需用strace盯mysqld线程是否长时间停在fsync(3),结合show engine innodb status中log sequence number与log flushed up to差距拉大、innodb_os_log_pending_fsyncs非零持续上升、iostat的%util>80%且await>10ms、iotop确认mysqld大量刷盘等多维度证据综合判定。

事务提交慢,八成是磁盘IO卡在fsync上,不是SQL写得差。
怎么确认卡在fsync而不是SQL执行本身
别急着改配置,先抓证据。MySQL事务提交慢,本质常是innodb_flush_log_at_trx_commit=1(默认值)导致每次COMMIT都调用fsync(3),而磁盘响应不过来。
- 用
strace -p $(pgrep mysqld | head -1) -e trace=fsync盯一个卡住的线程,看它是否长时间停在fsync(3)调用上 - 查
SHOW ENGINE INNODB STATUS\G里的LOG段:Log sequence number和Log flushed up to差距持续拉大,说明日志刷盘跟不上写入速度 - 监控
Innodb_os_log_pending_fsyncs状态变量,非零且持续上升就是铁证
iostat和iotop怎么看才算真瓶颈
只看吞吐量会误判。MySQL写入慢多是随机小IO拖垮,不是带宽不够。
-
iostat -x 1重点盯两个指标:%util > 80%(设备饱和)、await > 10ms(单次IO等待过长),若两者同时出现且持续,基本坐实磁盘瓶颈 -
iotop -oP确认是不是mysqld进程在大量刷盘——尤其注意WRITE列里mysqld的IO占比是否主导 - 云盘场景(如阿里云ESSD、AWS gp3)必须查IOPS配额是否耗尽;
iotop -p $(pgrep mysqld)还能看到实际发出的写请求大小,小块写(4KB–16KB)密集时,IOPS比吞吐更关键
innodb_log_file_size太小也会拖慢COMMIT
日志文件小,InnoDB被迫高频checkpoint,把本该后台做的刷脏页动作推到前台事务里,表现为“每批提交突然卡一下”。
- 查当前值:
SHOW VARIABLES LIKE 'innodb_log_file_size'; - 估算:按峰值写入量算,至少容纳1–2分钟的
Innodb_os_log_written增速(单位字节/秒) - 不能在线改:必须停库 → 删除
ib_logfile0和ib_logfile1→ 修改配置 → 重启。否则启动失败报InnoDB: Error: log file ./ib_logfile0 is of different size - 别乱调
innodb_log_files_in_group:它只影响文件个数,不改变总容量;真正起作用的是innodb_log_file_size × innodb_log_files_in_group
autocommit关了会导致“假慢”
很多ORM或连接池默认关闭autocommit,结果所有DML都堆在一个事务里,最后COMMIT才爆发式刷盘——这不是慢,是压根没提交。
- 连上就查:
SELECT @@autocommit;,生产环境应为1 - Python项目检查是否调用了
conn.autocommit(False)或conn.begin();Spring Boot重点看spring.datasource.hikari.auto-commit是否被误设为false - 批量插入务必用
INSERT INTO t VALUES (),(),()...,别用循环单条;每批500–2000行较稳,太多易触发锁升级或max_allowed_packet超限
真正难处理的点在于:磁盘IO问题往往混着多个因素——比如innodb_log_file_size偏小 + innodb_flush_log_at_trx_commit=1 + 云盘IOPS突发耗尽,三者叠加会让延迟陡增,但单独看每个指标可能都“勉强合格”。排查时得一层层剥,不能只盯着一个参数调。











