innodb_undo_log_truncate=on仅是许可开关,需同时满足innodb_undo_tablespaces≥2、非只读模式、purge完成且历史列表清空等条件才触发逻辑截断,不释放磁盘文件空间。

开启 innodb_undo_log_truncate 不等于 Undo 文件会自动变小——它只允许 InnoDB 在满足严格条件时逻辑截断表空间,而文件尺寸在磁盘上保持不变。
为什么开了 innodb_undo_log_truncate=ON 却没反应
这不是配置错了,而是触发条件未满足。该参数只是“许可开关”,不是“执行指令”。真正触发需同时满足:
-
innodb_undo_tablespaces ≥ 2(必须是多个独立 undo 表空间,单ibdata1完全无效) - 系统处于非只读模式(
super_read_only=OFF、read_only=OFF) - 至少有一个 undo 表空间中存在已 purge 完毕的历史段(即
TRX_RSEG_HISTORY_SIZE极小,且对应HISTORY LIST已清空) - InnoDB 每 128 秒轮询一次,不实时响应
常见误判:看到错误日志里没有 [Note] InnoDB: Truncating tablespace 就认为失败,其实可能只是 purge 还没跑完、或历史段仍被长事务/慢查询持有。
如何确认当前 undo 是否支持 truncate
分三步快速验证:
- 查变量:
SHOW VARIABLES LIKE 'innodb_undo%';—— 确认innodb_undo_tablespaces≥ 2 且innodb_undo_log_truncate为ON - 查表空间:
SELECT NAME, SPACE_TYPE, STATE, FILE_SIZE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE SPACE_TYPE = 'Undo';—— 确保有多个STATE = 'active'的 undo 表空间 - 查 purge 进度:
SELECT HISTORY_LIST_LENGTH FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'history_list_length';—— 值持续为 0 或个位数才说明 purge 已跟上
若 HISTORY_LIST_LENGTH 长期 > 10000,说明 purge 线程滞后,需调高 innodb_purge_threads 或检查是否有未提交事务/长查询阻塞。
truncate 后文件大小没变?这是正常设计
这是最常被误解的一点:TRUNCATE 操作仅重置表空间内部 LSN 和页分配状态,**不释放操作系统文件空间**。你用 ls -lh 看到的 undo_001 大小不会下降。
- MySQL 8.0.30+ 才支持
OPTIMIZE TABLESPACE undo_001;(在线收缩物理文件) - 低于该版本,唯一能缩小文件的方法是停库 + 重建 undo 表空间拓扑(删旧文件、重启生成新文件)
- 不要手动
rm或truncateundo 文件,会导致启动失败并报错InnoDB: Error: log file ./undo_001 is missing
日常运维中,应把重点放在监控 FILE_SIZE 增长趋势和 HISTORY_LIST_LENGTH,而非盯着磁盘占用是否“立刻减少”。
生产环境启用前必须检查的三件事
跳过任一环节都可能导致启动失败或配置静默失效:
- 确认
innodb_undo_directory目录存在、属主为mysql:mysql、权限为700,且不在/tmp或/var/tmp等会被系统清理的路径下 - 检查 my.cnf 加载路径是否正确:
mysqld --help --verbose | grep "default",避免改了错的配置文件 - 若从 5.7 升级或旧实例未启用独立 undo,不能直接加参数重启——必须先停库、备份、删掉原有
ibdata1和undo_*文件(⚠️仅限新部署或已确认 purge 完毕的环境)
真正生效的标志不是参数开了,而是 INFORMATION_SCHEMA.INNODB_TABLESPACES 中出现多个 Undo 类型条目,且后续观察到 HISTORY_LIST_LENGTH 可稳定回落。











