大事务直接拖慢checkpoint推进,核心是undo日志膨胀与脏页堆积双重卡死,解法为拆事务、控脏页、监checkpoint age;调大日志文件无效。

大事务直接拖慢 checkpoint 推进,不是配置不合理,而是 undo 日志膨胀 + 脏页堆积双重卡死。核心解法是“拆事务 + 控制脏页 + 监控 checkpoint age”,不是调大日志文件。
为什么大事务会让 checkpoint 卡住
一个未提交的大事务(比如 UPDATE 百万行)会持续生成 undo log,并阻止 purge 线程清理旧版本;同时大量脏页无法刷盘(因为要保证 crash recovery 时能回滚),导致 Log sequence number 和 Last checkpoint at 差值越拉越大——InnoDB 只能在差值达到总 redo log 容量 70% 时强制 checkpoint,而大事务让这个过程变得极其缓慢。
常见现象包括:
-
Innodb_log_waits持续增长 -
SHOW ENGINE INNODB STATUS\G中LOG部分显示Log checkpoint age长期 > 80% 容量 - 写入 QPS 下降,
COMMIT延迟飙升,甚至触发Lock wait timeout exceeded
必须立刻做的三件事
别等重启,先止损:
- 查出并杀掉长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60;,对TRX_STATE = 'RUNNING'且耗时超 60 秒的,用KILL干掉 - 确认是否真有未提交事务阻塞 purge:
SHOW ENGINE INNODB STATUS\G→ 找TRANSACTIONS部分,看是否有ROLLING BACK或长时间RUNNING的事务 - 临时降低脏页压力:执行
SET GLOBAL innodb_max_dirty_page_pct = 50;(注意这不是长期方案,只是缓解)
如何避免下次再卡住
关键不在日志大小,而在事务行为本身:
- 批量操作必须分批提交:每批最多 5000 行,用
WHERE id BETWEEN ? AND ?或时间范围切片,应用层控制循环+COMMIT - 禁用
AUTOCOMMIT=0后手动开大事务:除非业务强依赖,否则默认应保持AUTOCOMMIT=1 - 监控
Innodb_os_log_written差值 +Innodb_log_waits,设置告警阈值(如 30 秒内Innodb_log_waits> 0 就发短信) - 不要靠调大
innodb_redo_log_capacity来掩盖问题——它只会让崩溃恢复更慢,不解决 checkpoint 推进慢的根本原因
MySQL 8.0.30+ 特别注意
你不能用 innodb_log_file_size 了,这个参数已废弃。如果配置里还留着,MySQL 启动直接报错:Unknown variable 'innodb_log_file_size'。只保留 innodb_redo_log_capacity,单位是字节(不是 MB),例如设 2GB 就写 2147483648。
但更要紧的是:哪怕你把 innodb_redo_log_capacity 设到 10GB,只要存在一个 10 分钟没提交的事务,checkpoint 就依然卡在那儿不动——日志容量再大,也救不了被锁死的 purge 和刷盘逻辑。


















