必须先查innodb_trx表定位真正卡住purge的事务;高危长事务特征为trx_state='running'、trx_query is null、持续时间超600秒,其readview未释放导致purge线程停滞,需用trx_mysql_thread_id关联processlist确认来源后谨慎kill。

必须先查 INNODB_TRX 表定位真正卡住 purge 的事务,否则所有后续操作都可能加剧风险;SHOW PROCESSLIST 的 Time 字段完全不可信,它不反映事务开启时长,只记录当前语句执行时间。
怎么用 INNODB_TRX 准确定位高危长事务
真正钉住 undo 的,是那些 trx_state = 'RUNNING' 且 trx_query IS NULL 的空闲事务——它们已挂起数小时,但 ReadView 未释放,导致 purge 线程寸步难行。
- 运行这个语句:
SELECT trx_id, trx_started, TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS duration_sec, trx_state, 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、trx_state = 'RUNNING'、trx_query IS NULL的记录;这类事务 99% 是应用崩溃后连接未关闭,或 ORM 未显式commit/rollback -
trx_rows_modified > 10000的写事务要立刻干预——回滚可能耗时数分钟,且会挤占大量 IO - 用
trx_mysql_thread_id关联information_schema.PROCESSLIST,确认HOST、USER、COMMAND,避免误杀定时任务或备份连接
为什么盲目 KILL 会让问题更严重
KILL 操作本身不是清理动作,而是触发状态切换。不同 trx_state 对应完全不同的底层行为,错判就会让实例雪崩。
-
trx_state = 'RUNNING'且trx_query IS NULL:可安全KILL,大概率是泄漏连接 -
trx_state = 'LOCK WAIT':说明它被别的事务堵住,先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游 -
trx_state = 'ROLLING BACK':绝对不要KILL,此时 InnoDB 正在同步回滚,KILL会让其转为异步,IO 爆涨、purge 停摆 - 若
History list length > 10000,批量KILL必须加SLEEP(0.2)间隔,否则瞬间 IO 冲突可能拖垮整个实例
执行前必须确认的三个隐藏风险点
很多 DBA 在 KILL 后发现空间没释放、甚至 ALTER UNDO TABLESPACE TRUNCATE 报错,往往是因为忽略了这三个硬性前提。
- 确认已启用独立 undo 表空间:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces';返回值必须 ≥ 4(仅 ≥ 2 不够轮换) - 确认
innodb_undo_log_truncate = ON已生效,且 purge 进度在推进:SHOW ENGINE INNODB STATUS\G中 “PURGE DONE for trx's n:o” 后的数字必须持续增长 - 备份工具如
mysqldump或mydumper若带--single-transaction,其自身连接也会开启长事务——查PROCESSLIST时别把它当“异常”误杀,但必须确保它在KILL高危事务之后再启动
最危险的操作不是不做,而是只做一半:比如只调大 innodb_purge_batch_size 却不杀源头事务,或只开 innodb_undo_log_truncate 却没等 PURGE DONE 推进就急着 TRUNCATE。Undo 膨胀问题里,顺序就是安全边界。











