必须先终止trx_state = 'running'且trx_query is null的长事务,否则purge无法清理历史版本;需用innodb_trx按trx_started排序定位超600秒事务,关联processlist确认后分类kill,再调大innodb_purge_batch_size并启用undo截断。

必须先查 INNODB_TRX 找出真正卡住 purge 的长事务,否则所有磁盘清理动作都只是隔靴搔痒。
怎么快速定位卡住 purge 的长事务
别信 SHOW PROCESSLIST 的 Time 字段——它只反映当前语句执行时长,和事务开启时间无关。真正钉死 undo 的,是那些早已空闲却没提交的连接。
- 运行:
SELECT trx_id, trx_started, trx_state, trx_rows_modified, trx_mysql_thread_id FROM information_schema.INNODB_TRX ORDER BY trx_started LIMIT 5 - 重点关注:
trx_state = 'RUNNING'且trx_query IS NULL、trx_started超过 600 秒(10 分钟)的记录 -
trx_rows_modified > 10000的写事务要优先处理;trx_rows_modified = 0的只读事务虽不新增 undo,但也会阻塞 purge - 用
trx_mysql_thread_id关联information_schema.PROCESSLIST,查HOST、USER、COMMAND和INFO,确认是否为异常挂起(比如 Python 进程崩溃但连接未 close)
为什么 kill 前必须看 trx_state
盲目 KILL 可能让实例雪崩,不同状态必须区别对待:
-
trx_state = 'RUNNING'且trx_query IS NULL:可安全KILL,99% 是应用漏了COMMIT或连接池未close -
trx_state = 'LOCK WAIT':说明被别的事务堵住了,先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游事务 -
trx_state = 'ROLLING BACK':千万别动,此时KILL会让回滚从同步变异步,IO 更爆、耗时翻倍,甚至拖垮 purge 线程 - 若
trx_rows_modified > 100000,回滚可能持续数分钟,KILL前务必评估业务影响
杀完之后 History list length 为何不降
杀掉源头事务后,HISTORY LIST LENGTH 不会立刻下降,因为 purge 线程还没来得及推进。
- 先确认 purge 是否在跑:
SHOW ENGINE INNODB STATUS\G,找PURGE DONE for trx's n:o后的数字是否持续增长 - 临时加大清理能力:
SET GLOBAL innodb_purge_batch_size = 10000(默认 300) - 加快截断频率:
SET GLOBAL innodb_purge_rseg_truncate_frequency = 16(默认 128) - 确保已启用独立 undo 表空间:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces',值必须 ≥ 2;若为 0,说明 undo 全挤在ibdata1里,TRUNCATE根本无效
最易被忽略的一点:即使 purge 推进完成、ALTER UNDO TABLESPACE ... TRUNCATE 执行成功,du -h 看到的文件大小也不会变——截断只是逻辑清零,物理空间释放需 MySQL 8.0.30+ 的 OPTIMIZE TABLESPACE,或停库重建 undo 文件。











