必须先终止trx_state='running'且trx_query is null的最老事务,否则innodb_undo_log_truncate无效;它仅对独立undo表空间中无依赖的已提交段生效,需配合调大innodb_purge_batch_size、降低innodb_purge_rseg_truncate_frequency并确保innodb_undo_tablespaces≥4才能真正释放空间。

Undo Log 配置不能单独提升事务性能,它只在长事务、高并发或MVCC读压力大的场景下显现出明显影响;盲目调参反而可能引发 purge 延迟、磁盘暴涨甚至卡顿。
为什么 innodb_undo_log_truncate 开了但磁盘还在涨?
这不是参数没生效,而是最老活跃事务还没结束——innodb_undo_log_truncate 只对“已提交且无事务依赖”的 undo 段生效。只要存在 trx_state = 'RUNNING' 且 trx_query IS NULL 的长事务,purge 线程就无法清理对应版本链,新 undo 持续写入,旧的堆着不释放。
- 先查真凶:
SELECT trx_id, trx_started, TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS duration_sec, trx_state, trx_rows_modified, trx_query FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 600; - 重点关注
duration_sec > 600且trx_rows_modified > 0的写事务;trx_rows_modified = 0但持续时间长的只读事务也要处理(它长期持快照阻塞 purge) -
innodb_undo_log_truncate仅对独立 undo 表空间(如undo_001)有效,若仍用ibdata1(共享系统表空间),该参数直接跳过
哪些参数必须配合调整才能让 purge 跟上节奏?
单独改 innodb_max_undo_log_size 或开截断,不如强化 purge 能力。关键不是“多大”,而是“清得多快、多及时”。
-
innodb_purge_threads:默认 4,高并发写场景建议设为 8~16(不超过 CPU 核心数的 1/2) -
innodb_purge_rseg_truncate_frequency:默认 128,即每 128 次 purge 才检查一次回滚段是否可截断;建议压到 16~50,加快释放频率 -
innodb_purge_batch_size:默认 300,可临时设为 10000(运行时动态调整:SET GLOBAL innodb_purge_batch_size = 10000;) -
innodb_max_purge_lag+innodb_max_purge_lag_delay是节流阀,不是清洁工;设500000+100000可防雪崩,但不能替代主动清理
独立 undo 表空间怎么配才真正生效?
MySQL 5.7+ 必须启用独立 undo 表空间,否则所有 truncate 和 size 控制都形同虚设。
- 确认已启用:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces';—— 值需 ≥ 4(MySQL 8.0 默认 2,但至少 4 才能触发自动截断逻辑) - 配置路径:
innodb_undo_directory = /data/mysql/undo/(务必提前mkdir -p并赋权,MySQL 启动时不会自动创建) - 大小控制:
innodb_max_undo_log_size = 2147483648(2G),避免单个文件过大导致截断耗时过长;值太小会频繁触发,值太大 purge 跟不上 - 加密敏感数据:
innodb_undo_log_encrypt = ON,但需确保密钥环插件已加载且密钥安全,否则启动失败
最容易被忽略的实操细节
配置改完重启 MySQL 不等于生效——很多参数是动态变量,但部分(如 innodb_undo_directory)必须重启;而 purge 相关参数即使动态生效,也依赖当前 History list length 是否已积压。
- 验证 purge 进度:
SHOW ENGINE INNODB STATUS\G→ 查 “History list length”,持续 > 10000 就说明 purge 严重滞后 - 别信
PROCESSLIST.TIME,它只反映当前语句执行时长;真正钉死 undo 的是INNODB_TRX.trx_started时间 - KILL 长事务前,务必 JOIN
information_schema.PROCESSLIST确认来源 IP、用户、DB,避免误杀核心业务连接 - 事务回滚本身开销大:一个修改了 10 万行的事务 rollback,undo 回放可能比原操作更慢,且全程阻塞 purge











