设为2未提速是因底层日志链路卡住:innodb_log_file_size过小触发频繁checkpoint、innodb_log_buffer_size不足致大事务反复刷缓存、innodb_io_capacity未按SSD实际IOPS配置,三者需同步优化。

为什么设 innodb_flush_log_at_trx_commit=2 后写入没变快?
不是参数没用,而是底层日志链路卡住了。常见现象是 TPS 不涨、innodb_row_lock_time 上升、Threads_running 波动剧烈。根本原因往往在三处:
-
innodb_log_file_size太小 → checkpoint 频繁触发,批量刷脏页阻塞新写入 -
innodb_log_buffer_size不足 → 大事务(如单批插入 >1MB)反复 flush buffer,抵消了设为 2 的收益 -
innodb_io_capacity和innodb_io_capacity_max没按 SSD 实际 IOPS 设置 → 刷盘线程跟不上 redo log 生成速度
改完必须同步校准这三项,否则 innodb_flush_log_at_trx_commit=2 就是“半截优化”。
如何让组提交真正生效?
MySQL 8.0 默认开启 binlog 组提交,但实际是否起效,取决于 sync_binlog 和 innodb_flush_log_at_trx_commit 的组合:
-
sync_binlog=1+innodb_flush_log_at_trx_commit=1→ 组提交被阉割成串行刷盘,吞吐掉一半以上 -
sync_binlog=1+innodb_flush_log_at_trx_commit=2→ InnoDB 日志进 OS cache,binlog 强制刷盘,组提交可正常聚合,生产常用折中方案 -
sync_binlog=0→ binlog 只写页缓存,风险高但吞吐最高,仅适合从库或日志可丢场景
验证是否真有组提交:查 SHOW GLOBAL STATUS LIKE 'Binlog_group_commit_trigger_count',非零说明有聚合;若 Binlog_group_commit_trigger_lock_wait 猛增,大概率是事务卡在锁上,组提交根本没机会启动。
批量提交该设多大才合理?
不是越大越好,也不是固定值。关键看业务容忍和系统负载:
- 单事务控制在 1–5 万行以内,具体取决于平均行宽和并发压力
- 建议每 100–1000 条 DML 批量提交一次,比如导入 10 万行,分 100 批、每批 1000 行
- 避免在事务里执行耗时逻辑(如网络请求、文件读写),否则锁持有时间不可控
- 应用层用
addBatch()/executeBatch()或 ORM 的批量接口实现,比手动拼 SQL 更稳
过长事务会拖慢 purge、膨胀 undo 表空间、拉长 MVCC 版本链,最终让查询也变慢。
为什么关 autocommit 之后反而更慢?
关了 autocommit 却不显式管理事务边界,是最常见的误用:
- 只执行
SET autocommit = 0,但忘了BEGIN和COMMIT→ 所有语句仍在隐式事务里,锁没释放,性能无改善 - 长期保持
autocommit=0不提交 → 连接持续持有锁、阻塞其他事务,还可能被wait_timeout中断 - 异常路径没写
ROLLBACK→ 连接卡在未结束事务状态,后续请求全被 hang 住
正确做法:批量操作前 SET autocommit = 0,再 BEGIN → 执行多条 DML → COMMIT 或 ROLLBACK → 最后 SET autocommit = 1 恢复默认。连接复用时这点尤其容易漏。











