必须先杀掉 trx_state = 'RUNNING' 且 trx_query IS NULL 的空闲事务,否则 purge 调优无效;这类事务不释放 ReadView,钉死历史版本链;需通过 INNODB_TRX 定位最老事务,结合 PROCESSLIST 确认后精准 KILL,并按状态分类处理,再手动助推 purge 进度。

必须先杀掉 trx_state = 'RUNNING' 且 trx_query IS NULL 的空闲事务,否则所有 purge 调优和参数修改都无效——这类事务不释放 ReadView,直接钉死整个历史版本链。
查真凶:用 INNODB_TRX 定位卡住 purge 的最老事务
别信 SHOW PROCESSLIST 的 Time 字段,它只统计当前语句执行时长。真正拖垮 purge 的,是那些早已执行完、却没 COMMIT 或 ROLLBACK 的连接:
- 运行
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_started超过 600 秒、trx_state = 'RUNNING'、且trx_query IS NULL的记录 -
trx_rows_modified = 0表示只读事务,危害较小;trx_rows_modified > 10000且长时间未提交,则极可能正在批量写入或已卡死 - 用
trx_mysql_thread_id关联information_schema.PROCESSLIST,确认HOST、USER、COMMAND和INFO,避免误杀后台定时任务或导出作业
KILL 前必须看 trx_state,三类状态处理方式完全不同
盲目 KILL 可能让回滚更慢、IO 更爆,甚至拖垮 purge 线程:
-
trx_state = 'RUNNING'且trx_query IS NULL:99% 是应用层漏了COMMIT或连接池泄漏,可安全KILL对应trx_mysql_thread_id -
trx_state = 'LOCK WAIT':它被别的事务堵住了,先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游事务 -
trx_state = 'ROLLING BACK':别动!此时 InnoDB 正在同步回滚,KILL会让其转为异步,反而延长清理时间、加剧 IO 压力 - 若
trx_rows_modified > 100000,回滚可能持续数分钟,KILL前务必评估业务影响并通知负责人
杀完后手动助推 purge,否则 History list length 不会下降
终止源头事务后,History list length 不会立刻回落,需主动干预 purge 进度:
- 检查当前进度:
SHOW ENGINE INNODB STATUS\G,关注 “PURGE DONE for trx's n:o < XXX” 行,对比刚杀掉的trx_id是否已被覆盖 - 临时加大清理力度:
SET GLOBAL innodb_purge_batch_size = 10000(默认 300),加快单次 purge 处理量 - 确认启用独立 undo 表空间:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces',值必须 ≥ 2(推荐设为 4) - 开启自动截断:
SET GLOBAL innodb_undo_log_truncate = ON,再对 inactive 的 undo 表空间执行ALTER UNDO TABLESPACE undo_001 TRUNCATE
关键点在于:innodb_undo_log_truncate 不是“一键清空”,它只在 History list length < 10000、无活跃事务引用、且至少有 2 个 active undo 表空间的前提下才生效。很多 DBA 卡在这一步,是因为忘了先新增第 3 个 undo 表空间,再设旧的为 INACTIVE——跳步必失败。


















