必须先终止trx_state='running'且trx_query is null的事务,否则purge线程被卡在最老readview,history list length只增不减;需用innodb_trx查运行超600秒、空闲未提交事务,结合processlist排除合法长连接后安全kill。

必须先终止 trx_state = 'RUNNING' 且 trx_query IS NULL 的事务,否则所有调参都无效——Purge 线程会被卡在最老 ReadView 处,History list length 只增不减。
怎么快速定位真正卡住 Purge 的长事务
别信 SHOW PROCESSLIST 的 Time 字段,它只统计当前语句执行时长;真正钉死 Purge 的是那些早已空闲、却没提交的连接。
- 运行
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; - 重点筛选:
trx_state = 'RUNNING'且trx_query IS NULL(99% 是应用漏COMMIT或连接池未close) - 再用
trx_mysql_thread_id关联information_schema.PROCESSLIST,确认HOST、USER和COMMAND,排除监控/备份等合法长连接
kill 前必须分状态判断,否则可能更糟
盲目 KILL 不仅无效,还可能让 IO 更爆、Purge 更慢,甚至引发雪崩。
-
trx_state = 'RUNNING'且trx_query IS NULL:可安全KILL,大概率是连接泄漏或 ORM 事务未关闭 -
trx_state = 'LOCK WAIT':先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游持锁者 -
trx_state = 'ROLLING BACK':别动,此时KILL会让回滚从同步变异步,耗时翻倍、IO 更爆 - 若
History list length > 10000,批量KILL必须加SLEEP(0.2)间隔执行,避免 Purge 线程瞬间过载
杀完后怎么让 Purge 跟上并触发 undo 截断
杀掉源头不等于问题结束——History list length 不会立刻下降,得主动助推。
- 检查 Purge 进度:
SHOW ENGINE INNODB STATUS\G,关注PURGE DONE for trx's n:o是否在推进 - 临时加大清理能力:
SET GLOBAL innodb_purge_batch_size = 10000(默认 300) - 确认已启用独立 undo 表空间:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces',值必须 ≥ 4(推荐) - 开启自动截断:
SET GLOBAL innodb_undo_log_truncate = ON - 再执行:
ALTER UNDO TABLESPACE undo_001 TRUNCATE
最容易被忽略的是:Purge 滞后从来不是参数问题,而是那个 trx_query IS NULL 却挂着超过 10 分钟的事务 ID。它不产生新 undo,却持续挡路——定位它、杀掉它,比翻文档调十次参数都直接。











