innodb_undo_log_truncate开启后不会缩小undo001文件大小,仅逻辑截断并重置LSN;必须满足独立undo表空间(innodb_undo_tablespaces≥2)、非只读、purge完成等前提才生效。

innodb_undo_log_truncate 开启后不会自动让 undo001 文件变小——这是最常见的误解。它只在满足严格前提时,逻辑标记截断并重置 LSN,而文件尺寸在操作系统层面完全不变。
为什么开了 innodb_undo_log_truncate = ON 却没效果?
根本原因不是配置漏了,而是拓扑不支持:innodb_undo_log_truncate 仅对**独立 undo 表空间**生效,且必须同时满足:
-
innodb_undo_tablespaces ≥ 2(推荐 ≥3,单个或 0 无效) - 系统非只读模式(
read_only = OFF) - 存在已 purge 完毕的历史 undo 段(即没有长事务卡住 purge)
- undo 表空间处于 active 状态,且其中至少一个 rseg 使用率极低(
TRX_RSEG_HISTORY_SIZE小)
phpEnv、Docker 默认初始化通常用的是 innodb_undo_tablespaces = 0,所有 undo 都塞进 ibdata1,此时开 innodb_undo_log_truncate 完全无意义。
如何确认当前 undo 是独立表空间还是共享的?
运行这条 SQL:
SELECT NAME, SPACE, TYPE, STATE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME LIKE '%undo%';
结果中若出现 innodb_undo_001、innodb_undo_002 这类名称,且 TYPE = 'Undo',说明是独立表空间;若只有 ibdata1 出现在 INFORMATION_SCHEMA.INNODB_TABLESPACES 里(或查不到任何 undo 记录),大概率还在共享表空间中。
再补查变量:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces';
如果返回 0 或空,就坐实了——你没独立 undo,别折腾 truncate 了。
想真正收缩 undo 文件大小,只能靠轮换 + 手动清理
即使配置全对、条件满足,truncate 也只是把文件内容逻辑清空、LSN 归零,du -h undo001 看到的大小依然纹丝不动。要释放磁盘空间,只有两条路:
-
MySQL 8.0.30+:执行
OPTIMIZE TABLESPACE undo001;(需表空间为 active 状态,且 purge 已完成) -
通用方案(含 5.7/8.0):新增一个 undo 表空间 → 把膨胀的那个设为
INACTIVE→ 等 purge 完成 →DROP UNDO TABLESPACE undo001;
注意:DROP 前必须确保该表空间里所有回滚段都已释放(查 INFORMATION_SCHEMA.INNODB_TRX 和 INFORMATION_SCHEMA.INNODB_ROLLBACK_SEGMENTS),否则会报错 ERROR 3134 (HY000): Cannot drop active undo tablespace。
最容易被忽略的点:purge 卡住,truncate 就永远不触发
很多人配完参数发现日志里从没出现 [Note] InnoDB: Truncating tablespace,第一反应是配置错了。其实更可能是 purge 被拖住了——比如有运行数小时的慢查询、未提交事务、或 innodb_purge_rseg_truncate_frequency 太大(默认 128)。
可临时加快 purge 节奏:
SET GLOBAL innodb_purge_rseg_truncate_frequency = 16;
再观察 SHOW ENGINE INNODB STATUS\G 中的 HISTORY LIST 长度是否持续下降。只要 HISTORY LIST 不归零,undo 就无法真正回收。


















