必须先杀掉trx_state='RUNNING'且trx_query IS NULL的事务,否则purge线程卡在最老ReadView导致所有调参和截断无效;需用INNODB_TRX按trx_started筛选超600秒的空闲事务,关联PROCESSLIST确认后分类KILL,再加大innodb_purge_batch_size并执行ALTER UNDO TABLESPACE TRUNCATE释放磁盘空间。

必须先杀掉 trx_state = 'RUNNING' 且 trx_query IS NULL 的事务,否则所有参数调优、截断操作都无效——这不是建议,是前提条件。
怎么快速定位真正卡住 purge 的长事务
别信 SHOW PROCESSLIST 的 Time 字段,它只反映当前语句执行时长,和事务开启时间完全无关。真正钉死 undo 的,是那些早已空闲但没提交的连接。
运行这条语句查最老的活跃事务:
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 ORDER BY trx_started LIMIT 5;
-
duration_sec > 600且trx_state = 'RUNNING'且trx_query IS NULL:99% 是应用崩溃后连接未关闭,或 ORM 忘了commit/rollback,必须优先处理 -
trx_rows_modified > 10000且duration_sec > 300:大写事务已卡住,回滚可能耗时数分钟,需立刻干预 - 用
trx_mysql_thread_id关联information_schema.PROCESSLIST,确认HOST、USER、INFO,避免误杀定时任务或导出作业
kill 前必须分状态处理,否则可能更糟
盲目 KILL 会拖垮 purge 线程、加剧 IO 压力,甚至让实例雪崩。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
trx_state = 'RUNNING'且trx_query IS NULL:可安全KILL对应线程,这是最常见、最该优先清理的泄漏源 -
trx_state = 'LOCK WAIT':它被别的事务堵住了,先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游事务 -
trx_state = 'ROLLING BACK':千万别动!此时KILL会让回滚从同步变异步,IO 更爆、purge 更慢 - 若
History list length > 10000,批量KILL必须加SLEEP(0.2)间隔执行,否则 purge 线程瞬间过载
杀完之后怎么让 undo 空间真正释放
杀掉源头事务后,History list length 不会立刻下降,必须手动助推 purge 并触发截断。
- 先检查进度:
SHOW ENGINE INNODB STATUS\G,关注 “PURGE DONE for trx's n:o ” 是否在持续推进,对比刚杀掉的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,再执行ALTER UNDO TABLESPACE undo_001 SET INACTIVE→ 等History list length显著回落 →ALTER UNDO TABLESPACE undo_001 TRUNCATE
最容易被忽略的一点:所有配置项(如 innodb_max_purge_lag、innodb_max_undo_log_size)都只是辅助手段,它们不解决“事务没结束”这个根本问题。只要还有一个 trx_state = 'RUNNING' 且 trx_query IS NULL 的事务活着,undo 就不会真正释放,history list 就会继续堆积。










