Undo表空间膨胀本质是长事务卡住purge线程所致,必须先定位并终止trx_state='RUNNING'且trx_query IS NULL的最老活跃事务;仅开启innodb_undo_log_truncate无效,需满足innodb_undo_tablespaces≥2、purge完成等全部条件才能触发逻辑截断,物理文件收缩须用OPTIMIZE TABLESPACE(8.0.30+)或停库重建。

Undo 表空间不需要“恢复数据”时才收缩——它根本不是为恢复而存在,而是事务回滚和 MVCC 快照读的支撑结构。所谓“自动收缩”,其实是应对大事务拖慢 purge、导致 undo 文件持续膨胀后的被动清理机制,不是功能需求,是运维止损手段。
Undo 膨胀本质是 purge 卡住,不是“数据太多”
MySQL 8.0 的 undo 表空间不会因“备份/恢复操作”变大;它暴涨只有一种原因:最老活跃事务长期未提交,堵住 purge 线程。此时 HISTORY_LIST_LENGTH 持续上升,旧版本记录无法回收,undo 文件只能不断追加写入。
-
HISTORY_LIST_LENGTH > 10000且不下降 → 几乎肯定有长事务卡在RUNNING状态但trx_query IS NULL - 查
INNODB_TRX时重点关注TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 600且trx_state = 'RUNNING'的记录 - 搭配
PROCESSLIST查对应ID,确认是空闲连接忘COMMIT,还是慢查询真卡住
innodb_undo_log_truncate=ON 不等于“自动缩文件”
这个参数只是打开一个门缝:允许 InnoDB 在满足全部条件时,对某个 undo 表空间执行逻辑截断(reset LSN 和页分配位图),但它不删文件、不调 ftruncate()、磁盘上 ls -lh undo_001 大小纹丝不动。
- 必须同时满足:
innodb_undo_tablespaces >= 2、super_read_only = OFF、HISTORY_LIST_LENGTH ≈ 0 - InnoDB 每
innodb_purge_rseg_truncate_frequency秒(默认 128)轮询一次,不实时触发 - 日志里出现
[Note] InnoDB: Truncating tablespace ./undo/undo_001才算真正执行了逻辑截断
为什么不能直接 ALTER TABLESPACE undo001 ENGINE=InnoDB?
这条语句对 undo 表空间完全无效,既不报错也不起作用,属于历史误传。InnoDB 明确不支持对 undo 类型表空间执行 ENGINE=InnoDB 操作。
- 执行后
INNODB_TABLESPACES.FILE_SIZE和ALLOCATED_SIZE完全不变 - 错误日志里查不到任何相关记录
- 官方文档从未将其列为
undo管理手段,纯属社区过时经验
真正能释放磁盘空间的操作只有两个
逻辑截断(TRUNCATE)只清内容,不缩文件。要让 du -sh undo_001 数值下降,只剩两条路:
- MySQL 8.0.30+:用
OPTIMIZE TABLESPACE undo_001(仍不删文件,但可回收内部碎片,部分版本能小幅减小物理尺寸) - 低于 8.0.30 或急需空间:停库 → 手动删除
undo_001.ibu→ 重启 MySQL 让其自动生成新文件(仅限测试/新环境,生产慎用) - 绝对禁止
rm undo_001.ibu后不停库重启,会报错InnoDB: Error: log file ./undo_001 is missing并拒绝启动
实际中,最容易被忽略的是:你看到 undo_001 占用 71G,第一反应是“赶紧缩”,但真正该做的,是立刻查 INNODB_TRX 找出那个卡了 3 小时没 COMMIT 的连接——否则所有收缩操作都会静默失败。











