长事务卡住Purge线程是因为其活跃Read View强制保留对应undo log,尤其是trx_state = 'RUNNING'且trx_query IS NULL的“僵尸事务”,虽不产生新undo却持续阻塞purge,导致history list只增不减;降级隔离级别或调参均治标,唯有定位并KILL该类事务才能根治。

长事务为什么卡住Purge线程
Purge线程不是“不干活”,而是被明确禁止清理某些undo log——只要还有活跃事务的Read View里包含某个trx_id,对应的历史版本就必须保留。长事务没提交,它的Read View就一直有效,所有它开启后产生的旧版本都成了“钉子户”,purge线程只能绕着走。
trx_state = 'RUNNING' 且 trx_query IS NULL 是最危险的信号
这种事务早已执行完SQL,但既没COMMIT也没ROLLBACK,连接还挂着。它不产生新undo,却持续挡在purge路径上,导致HISTORY LIST LENGTH只增不减。这类事务在SHOW PROCESSLIST里Time字段往往为0或很小,容易被忽略。
- 查它:用
SELECT trx_id, trx_started, trx_state, trx_query, trx_mysql_thread_id FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING' AND trx_query IS NULL ORDER BY trx_started LIMIT 1 - 确认来源:关联
information_schema.PROCESSLIST查HOST和USER,大概率是Python/Java应用崩溃后连接未释放 - 别等:只要
trx_started超过600秒,优先KILL,比调任何参数都管用
READ COMMITTED 能缓解但不能替代事务管理
把隔离级别从REPEATABLE READ降到READ COMMITTED,确实能让部分undo更早释放——因为每个语句结束后就丢掉自己的Read View。但这只是减缓症状,不是根治:
- 对只读事务有效,对写事务影响有限(UPDATE/DELETE仍需保留undo直到事务结束)
- 业务逻辑若依赖RR的一致性快照(比如报表生成),降级后可能出错
- 如果应用层仍有空闲事务不提交,照样卡purge,只是卡得慢一点
innodb_max_purge_lag 不是清理开关,而是刹车片
innodb_max_purge_lag设再小,也不会让purge线程多干一点活;它只在HISTORY LIST LENGTH超阈值时,给新DML加usleep延迟。本质是用写入变慢换空间安全,治标不治本。
- 设为0:等于关闭保护,磁盘爆满风险直线上升
- 设为500000:较平衡,但前提是没长事务堵着——否则history list永远卡在10万以上
- 真正起效的前提:先清掉最老的
trx_state = 'RUNNING'且trx_query IS NULL事务
trx_query都为空的事务ID。定位它、杀掉它,比翻文档调十次参数都直接。


















