真正卡住purge的是最老未提交事务;需用INNODB_TRX查duration_sec>600、trx_state='RUNNING'且trx_query IS NULL的事务,再结合PROCESSLIST确认后安全KILL。

Undo Log 膨胀不是磁盘配额不够,而是长事务卡死了 purge 线程——只要有一个 trx_state = 'RUNNING' 且 trx_query IS NULL 的事务没提交,所有它开启时点之前的旧版本数据就全被钉住,无法清理。
怎么确认是哪个事务在卡 purge
SHOW PROCESSLIST 的 Time 字段完全不可信,它只统计当前语句执行时长,和事务生命周期无关。真正危险的是那些“空闲但未结束”的连接。
运行这个查询定位真凶:
SELECT trx_id, trx_started, TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS duration_sec, trx_state, trx_query, 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;
重点关注:
-
duration_sec > 600(10 分钟以上) trx_state = 'RUNNING'trx_query IS NULL-
trx_rows_modified > 10000(写得多、卡得久)
再用 trx_mysql_thread_id 去查 information_schema.PROCESSLIST,确认 HOST、USER 和 COMMAND,避免误杀定时任务或导出作业。
KILL 之前必须看状态,乱杀会更糟
不同 trx_state 对应完全不同处理逻辑:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
-
trx_state = 'RUNNING'且trx_query IS NULL:99% 是应用崩溃后连接残留或 ORM 忘记commit,可安全KILL -
trx_state = 'LOCK WAIT':它正被别的事务堵着,先查INNODB_LOCK_WAITS找出blocking_trx_id,干掉上游 -
trx_state = 'ROLLING BACK':千万别动,此时KILL会让回滚从同步变异步,IO 更爆、时间更长,还可能拖垮purge
若 trx_rows_modified > 100000,回滚可能持续数分钟;History list length > 10000 时批量 KILL,务必加 SLEEP(0.2) 间隔执行。
杀完为什么空间还不释放
杀掉源头事务后,History list length 不会立刻下降——purge 线程需要时间追平。不主动助推,undo 文件就一直占着磁盘。
检查进度:
SHOW ENGINE INNODB STATUS\G找
PURGE DONE for trx's n:o 行,对比刚 kill 掉的 <code>trx_id 是否已被覆盖。
临时加速:
-
SET GLOBAL innodb_purge_batch_size = 10000(默认 300) -
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1(默认 128,值越小越激进) - 确保
innodb_undo_tablespaces >= 4(仅 ≥2 不够轮换)
ALTER UNDO TABLESPACE undo_001 TRUNCATE 必须等 History list length 显著回落后再执行,否则直接报错。
真正卡住 purge 的,永远是最老那个没提交的事务;其他所有操作,都是给它擦屁股。

















