undo log膨胀本质是长事务卡住purge线程导致历史版本无法清理,必须先终止trx_state='running'且trx_query is null的最老事务,否则调参无效;需用innodb_trx按trx_started排序定位,关联processlist确认异常连接,依状态分类kill,再加大innodb_purge_batch_size并启用undo截断。

Undo Log 膨胀不是磁盘空间配置问题,是长事务卡住 purge 线程导致历史版本无法清理;不先终止 trx_state = 'RUNNING' 且 trx_query IS NULL 的事务,调任何参数都白搭。
怎么快速定位真正钉住 undo 的长事务
别信 SHOW PROCESSLIST 的 Time 字段——它只统计当前语句执行时长,而真正阻塞 purge 的,是那些已空闲、没提交、但还挂着 read view 的事务。
- 运行这条语句查最老的活跃事务:
SELECT trx_id, trx_started, TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS duration_sec, trx_state, trx_rows_modified, trx_mysql_thread_id FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 600 ORDER BY trx_started LIMIT 5 - 重点关注:
trx_state = 'RUNNING'+trx_query IS NULL+duration_sec > 600,这类基本是应用层漏了COMMIT或连接池未 close - 用
trx_mysql_thread_id关联information_schema.PROCESSLIST,查HOST、USER、INFO,确认是否来自 Python/Java 应用异常退出后残留的连接 -
trx_rows_modified = 0的只读事务也会阻塞 purge,但危害小;真正危险的是trx_rows_modified > 10000且长时间未提交的写事务
KILL 前必须分状态判断,否则可能雪崩
盲目 KILL 不仅不能释放空间,反而会让回滚更慢、IO 更爆,甚至拖垮 purge 线程。
-
trx_state = 'RUNNING'且trx_query IS NULL:可安全KILL,99% 是 ORM 事务泄漏或连接池未释放 -
trx_state = 'LOCK WAIT':它被别的事务堵住了,先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游事务 -
trx_state = 'ROLLING BACK':别动!此时KILL会让回滚从同步变异步,耗时翻倍、IO 更高 - 若
trx_rows_modified > 100000,回滚可能持续数分钟,KILL前务必评估业务影响 - 如果
SHOW ENGINE INNODB STATUS\G中History list length > 10000,批量KILL必须加SLEEP(0.2)间隔,否则 purge 线程直接被打死
杀完之后 undo 空间为什么还不释放?
杀掉源头事务后,History list length 不会立刻下降,undo 文件也不会自动收缩——InnoDB 不支持 online shrink。
- 先确认 purge 是否在推进:反复执行
SHOW ENGINE INNODB STATUS\G,看 “PURGE DONE for trx's n:o” 后的数字是否缓慢增长 - 临时加大 purge 能力:
SET GLOBAL innodb_purge_batch_size = 10000(默认 300),SET GLOBAL innodb_purge_rseg_truncate_frequency = 16 - 检查是否启用独立 undo 表空间:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces',值必须 ≥ 4;若为 0(即共享表空间ibdata1),undo 无法截断,只能重建实例 - 开启截断:
SET GLOBAL innodb_undo_log_truncate = ON,再执行ALTER UNDO TABLESPACE undo_001 SET INACTIVE→ 等History list length显著回落 →ALTER UNDO TABLESPACE undo_001 TRUNCATE - MySQL 8.0 要求至少保留 2 个 active 的 undo 表空间才能
TRUNCATE,别一次性设全 inactive
最容易被忽略的是:innodb_undo_log_truncate 不是“清空按钮”,它只在长事务全部结束、History list length 已很低、且后台每 128 秒检查满足条件时才触发裁剪;在此之前,所有调参都是缓震,不是根治。











