必须先杀掉trx_state='running'且trx_query is null的事务,否则所有调优无效;需用innodb_trx定位最老活跃事务,重点关注trx_started超600秒、trx_rows_modified>10000的写事务,关联processlist确认来源后按状态分类kill,再调大purge参数并启用独立undo表空间截断。

必须先杀掉 trx_state = 'RUNNING' 且 trx_query IS NULL 的事务,否则所有参数调优、截断操作都无效。
查真凶:用 INNODB_TRX 找出真正卡住 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_started超过 600 秒(10 分钟)、trx_state = 'RUNNING'、且trx_query IS NULL的记录 -
trx_rows_modified = 0表示只读事务,也会阻塞 purge,但危害小;trx_rows_modified > 10000的写事务才是高危目标 - 用
trx_mysql_thread_id关联information_schema.PROCESSLIST,查HOST、USER、COMMAND和INFO,确认是否为异常挂起的应用连接(比如 Python 进程崩溃后连接未关闭)
KILL 前必须看状态,乱杀会让问题更糟
KILL 不是万能解药。不同 trx_state 对应完全不同的处理逻辑,错一步就可能拖垮 purge 线程或引爆 IO。
-
trx_state = 'RUNNING'且trx_query IS NULL:99% 是应用漏了COMMIT或ROLLBACK,可安全KILL对应trx_mysql_thread_id -
trx_state = 'LOCK WAIT':它被别的事务堵住了,先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游事务 -
trx_state = 'ROLLING BACK':千万别动!此时 InnoDB 正在同步回滚,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 ” 行,对比 <code>trx_id看是否持续递增 - 临时加大清理力度:
SET GLOBAL innodb_purge_batch_size = 10000(默认是 300) - 确保已启用独立 undo 表空间:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces',值必须 ≥2(推荐设为 4) - 开启自动截断:
SET GLOBAL innodb_undo_log_truncate = ON,再对每个 undo 表空间执行:ALTER UNDO TABLESPACE undo_001 TRUNCATE
为什么 innodb_max_purge_lag 不能解决根本问题
这个参数只是节流阀,不是清洁工。它只在未 purge 的 undo 记录数超限时,给新写入加微秒级延迟,从而缓解压力,但对已堆积的 history list 和卡住的长事务毫无作用。
- 设成
0等于禁用保护,undo 持续膨胀直到磁盘满 - 设得太小(如 10000),正常批量导入也会被频繁 throttle,TPS 断崖下跌
- 调完参数却不查
INNODB_TRX里那个运行了 8 小时、trx_query IS NULL的事务,等于白调 - 真正起效的前提永远是:先干掉阻塞 purge 的长事务
最容易被忽略的是:ALTER UNDO TABLESPACE ... TRUNCATE 失败往往不是语法错,而是 purge 还没推进到对应回滚段——得等 HISTORY LIST LENGTH 降到 10000 以下,且对应 undo 表空间中没有活跃事务引用的页,截断才会真正生效。











