必须先杀掉trx_state='running'且trx_query is null的最老事务,否则调参、截断或purge加速均无效;需用innodb_trx按trx_started排序定位,关联processlist确认异常连接,分状态kill后加大innodb_purge_batch_size并启用undo截断。

必须先杀掉 trx_state = 'RUNNING' 且 trx_query IS NULL 的事务,否则所有参数调优、自动截断、purge 加速都无效。
怎么快速定位真正卡住 purge 的长事务
别信 SHOW PROCESSLIST 的 Time 字段——它只算当前语句执行时长,而真正钉死 undo 的,是那些早已空闲却没提交的连接。直接查 INNODB_TRX 表:
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—— 这类事务极大概率是应用崩溃后连接未关闭,或 ORM 未显式 commit -
trx_rows_modified > 10000且duration_sec > 300的写事务要立刻干预,回滚可能耗时数分钟 - 用
trx_mysql_thread_id关联information_schema.PROCESSLIST,确认HOST、USER、INFO,避免误杀定时任务或导出作业
kill 前必须分状态处理,否则可能更糟
盲目 KILL 会拖垮 purge 线程、加剧 IO 压力,甚至让实例雪崩:
-
trx_state = 'RUNNING'且trx_query IS NULL:可安全KILL对应线程,99% 是连接泄漏或事务未关闭 -
trx_state = 'LOCK WAIT':先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游事务 -
trx_state = 'ROLLING BACK':别动!此时 KILL 会让回滚从同步变异步,耗时翻倍、IO 更爆 - 若
trx_rows_modified > 100000,KILL 前务必评估业务影响;若History list length > 10000,批量 KILL 必须加SLEEP(0.2)间隔执行
杀完之后怎么让 undo 空间真正释放
杀掉源头事务后,History list length 不会立刻下降,必须手动助推 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',值必须 ≥ 4(仅 ≥ 2 不够轮换) - 开启自动截断:
SET GLOBAL innodb_undo_log_truncate = ON,再对每个 undo 表空间依次执行:ALTER UNDO TABLESPACE undo_001 SET INACTIVE→ 等History list length显著回落 →ALTER UNDO TABLESPACE undo_001 TRUNCATE
最容易被忽略的点是:innodb_undo_log_truncate = ON 只是开关,不是“清空按钮”。它每 128 秒检查一次,生效需同时满足三个条件——innodb_undo_tablespaces ≥ 2、History list length 、对应 undo 表空间中无活跃事务引用的页。跳过任一环节,<code>TRUNCATE 都会失败。











