Undo Log 过大导致 purge 线程卡住、事务变慢,根本原因是长事务阻塞清理,需调小 innodb_max_undo_log_size(128M~256M)、开启 innodb_undo_log_truncate、增加 innodb_purge_threads 数量,并监控长事务和 INNODB_METRICS 指标。

Undo Log 太大导致 purge 线程卡住,事务变慢
InnoDB 的 undo_log 不是写完就删,而是等所有依赖它的事务(包括长事务、未提交事务、MVCC 可见性需要的旧版本)都结束后,才由 purge 线程异步清理。如果 innodb_max_undo_log_size 设得过大(比如默认 1GB),单个 undo 表空间文件膨胀后,purge 扫描和回收效率会明显下降,尤其在高并发更新场景下,容易堆积大量未 purge 的 undo 记录,拖慢整个系统的响应。
实操建议:
-
innodb_max_undo_log_size建议设为 128M~256M(即134217728~268435456),避免单个 undo 表空间“一枝独大”; - 必须配合启用
innodb_undo_log_truncate=ON(MySQL 5.7+ 默认开启),否则调小该值无效; - 调整后需等待一次自动 truncate 周期(默认每 12800 秒触发一次,由
innodb_undo_log_truncate和innodb_max_undo_log_size共同控制)才会真正收缩文件; - 观察
SHOW ENGINE INNODB STATUS中的PURGE DONE进度,以及information_schema.INNODB_METRICS里undo_log_truncations计数是否上升。
为什么不能直接调小 innodb_undo_tablespaces 数量
很多人误以为减少 undo 表空间数量(innodb_undo_tablespaces)能降低开销,其实反了:它只影响 undo 表空间文件个数(默认 128),不控制总大小,也不影响 purge 效率。真正起作用的是每个表空间的上限(innodb_max_undo_log_size)和是否允许截断(innodb_undo_log_truncate)。
实操建议:
-
innodb_undo_tablespaces建议保持默认(128)或至少 ≥ 36,太少会导致多个 undo 段挤在一个文件里,反而加剧锁争用; - 该参数只能在实例初始化时设置(
mysqld --initialize阶段),运行中不可修改; - 如果已上线且值过小(如 2),不要强行改——没有安全在线调整路径,硬改会导致启动失败。
长事务是 undo 堆积的真正元凶,比参数调优更关键
再小的 innodb_max_undo_log_size 也扛不住一个运行 2 小时的未提交事务:它会阻止 purge 清理所有早于该事务快照的 undo 记录,导致 undo 文件持续增长、历史链变长、MVCC 查找变慢。这时调参只是掩耳盗铃。
实操建议:
- 用
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW()) - TIME_TO_SEC(TRX_STARTED) > 60定期查超 60 秒的活跃事务; - 监控
information_schema.INNODB_METRICS中undo_log_discarded(被丢弃的 undo 记录数)和undo_log_records(当前存活记录数),比看磁盘大小更有预警价值; - 应用层务必设置
wait_timeout和interactive_timeout(建议 ≤ 300),并避免在事务中做 RPC、文件读写等阻塞操作。
truncate 触发后 undo 文件没变小?别慌,这是正常现象
即使 innodb_undo_log_truncate=ON 且 innodb_max_undo_log_size 调小了,你看到 ibdata1 或独立 undo 文件(如 undo001)的磁盘大小也没变化——因为 InnoDB 只是把“可截断区域”标记为空闲,不会主动归还磁盘空间给操作系统。文件逻辑上变“轻”了,物理上还是那么大。
实操建议:
- 确认是否真的触发了 truncate:查
information_schema.INNODB_METRICS中undo_log_truncations是否递增; - 想真正缩文件,只能重建:导出数据 → 停库 → 删除
undo*文件 → 修改配置 → 初始化新实例 → 导入; - 日常运维中,只要
undo_log_truncations在涨、undo_log_records趋稳,就说明 purge 和 truncate 已生效,不必强求磁盘尺寸回落。
最常被忽略的一点:参数生效依赖 purge 线程健康度。如果 innodb_purge_threads 是 1(默认),而 undo 压力大,它可能根本忙不过来——这时候加 purge 线程数(比如设为 4)比死磕 innodb_max_undo_log_size 更立竿见影。



















