必须立即查innodb_trx找最老的“空闲未提交”事务(trx_state='running'且trx_query is null),再关联processlist确认状态,最后用history_list_length验证purge是否被堵死,漏任一环易误判导致io雪崩。

Undo表空间暴涨不是配置没开、也不是磁盘配额小,而是有事务卡住了purge线程——必须立刻查INNODB_TRX,否则所有后续操作都是白忙。
查INNODB_TRX找最老的“空闲未提交”事务
真正拖垮purge的,几乎全是trx_state = 'RUNNING'且trx_query IS NULL的事务。它们早已执行完语句,但应用层没发COMMIT或ROLLBACK,却一直占着最老read view。
- 运行:
SELECT trx_id, trx_started, trx_state, trx_rows_modified, trx_mysql_thread_id, TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS duration_sec FROM information_schema.INNODB_TRX ORDER BY trx_started LIMIT 5; - 重点关注
duration_sec > 600(10分钟)且trx_query IS NULL的记录 -
trx_rows_modified > 10000的写事务更要优先处理,哪怕只跑了300秒 - 别信
PROCESSLIST里的Time字段——它只统计当前语句耗时,对空闲连接完全无效
用PROCESSLIST确认线程来源和真实状态
拿到trx_mysql_thread_id后,必须关联查PROCESSLIST,否则你不知道该KILL谁、能不能KILL。
- 执行:
SELECT ID, USER, HOST, COMMAND, TIME, INFO FROM information_schema.PROCESSLIST WHERE ID = ?; - 若
COMMAND = 'Sleep'且INFO IS NULL,基本可判定是应用连接泄漏(如ORM未close session) - 若
COMMAND = 'Query'且INFO显示长UPDATE/DELETE,需结合执行计划判断是否真卡住 - 若
COMMAND = 'Killed'但线程还在,说明回滚中——此时trx_state = 'ROLLING BACK',千万别再KILL
看HISTORY_LIST_LENGTH验证purge是否被堵死
这个值不降,说明purge根本没动;它持续上涨,等于在报警:最老事务还没走,新undo只能硬追加。
- 执行:
SHOW ENGINE INNODB STATUS\G,在输出里搜History list length - 值长期>10000,基本可断定存在阻塞源;>100000说明问题已严重
- 同时检查
PURGE DONE for trx's n:o后的数字是否在缓慢增长——不涨=purge线程停滞或被锁死 - 注意:
innodb_purge_threads默认为1,高并发下建议设为4,否则单线程根本追不上
定位的关键不在“看多少指标”,而在顺序:先INNODB_TRX锁定最老事务ID,再PROCESSLIST确认它是不是挂起的空闲连接,最后用HISTORY_LIST_LENGTH交叉验证purge是否真被卡住——漏掉任一环,就容易把“正在回滚的大事务”误判为“可安全KILL的空闲连接”,结果让IO雪崩。











