MySQL 8.0 innodb_undo_log_truncate=ON 无效,根本原因是未满足四大硬性前提:innodb_undo_tablespaces≥2、innodb_max_undo_log_size>0、至少一个undo表空间空闲、且Purge线程必须活跃推进;其中innodb_undo_tablespaces初始化后不可动态修改,XA PREPARED事务会锁死整个空间,需人工清理。

为什么 SET GLOBAL innodb_undo_log_truncate = ON 没用
不是开关没开,而是 MySQL 8.0 根本不满足截断前提,会静默忽略该设置。最常被忽略的硬性条件有四个:innodb_undo_tablespaces 必须 ≥ 2、innodb_undo_log_truncate 必须为 ON、innodb_max_undo_log_size 必须 > 0、且至少一个 undo 表空间处于空闲状态(即无活跃事务绑定)。其中 innodb_undo_tablespaces 在初始化后不可动态修改,若值为 0 或 1,必须重建实例或在线添加新 undo 表空间才能补救。
手动触发 Purge 线程是绕过“等待自动判断”的关键
Undo 截断依赖 Purge 线程完成逻辑清理(即回收已提交事务的 undo 日志),而 innodb_purge_threads 默认仅 1 个,高负载下 purge 进度滞后,导致 undo 段长期无法标记为“可截断”。此时即使所有参数正确,TRUNCATE_STATUS 也始终卡在 not_truncate_ready。
- 先确认 purge 进度:执行
SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME LIKE 'purge%';,重点关注purge_trx_count和purge_undo_log_bytes是否持续下降 - 临时加速 purge:增大线程数,例如
SET GLOBAL innodb_purge_threads = 4;(注意:不要设过高,避免 I/O 冲突) - 强制唤醒 purge:执行
SELECT SLEEP(0);或任意轻量查询,可触发一次 purge 循环(非 guaranteed,但实测有效) - 检查 purge 是否被阻塞:查
INFORMATION_SCHEMA.INNODB_TRX中TRX_STATE = 'RUNNING'且TRX_STARTED超 30 分钟的事务,它们会拖住 purge 的 low watermark
TRUNCATE_STATUS 为 truncate_ready 后仍不截断?盯紧 innodb_undo_truncate_frequency
即使状态就绪,InnoDB 也不会立刻执行物理截断,而是按 innodb_undo_truncate_frequency(默认 128)控制频率:每完成 128 次 purge 操作才尝试一次截断判定。这个值太小会导致频繁 I/O,太大则延迟明显。
- 查看当前值:
SHOW VARIABLES LIKE 'innodb_undo_truncate_frequency'; - 如需加快响应,可设为 32 或 64,例如
SET GLOBAL innodb_undo_truncate_frequency = 32; - 注意:该变量仅在 purge 活跃时生效;若
innodb_purge_rseg_truncate_frequency(8.0.30+ 引入)也被调整,需同步协调,否则可能冲突
手动轮转 + 显式 SET INACTIVE 是最可控的释放路径
当自动机制反复失效,或急需快速释放某一个膨胀严重的 undo 表空间(比如 undo_001 达到 71G),应放弃等待,走显式管理流程:
- 先添加新 undo 表空间:
CREATE UNDO TABLESPACE undo_003 ADD DATAFILE 'undo_003.ibu'; - 将目标表空间设为非活跃:
ALTER UNDO TABLESPACE undo_001 SET INACTIVE; - 立即查状态:
SELECT NAME, STATE, TRUNCATE_STATUS FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME = 'undo_001';,直到STATE变为empty且TRUNCATE_STATUS为truncate_ready - 此时文件尚未收缩,但后续 purge 完成后会自动触发截断;若等不及,可配合
SET GLOBAL innodb_undo_log_truncate = ON;再观察几分钟
真正难的是判断“是否真空闲”——哪怕只剩一个 XA PREPARED 事务,整个 undo 表空间都会锁死。务必用 XA RECOVER; 扫一遍,残留状态必须人工 XA COMMIT 或 XA ROLLBACK,重启不管用。


















