必须先杀掉trx_state='RUNNING'且trx_query IS NULL的事务,否则purge无法推进、History list length不降;再加大innodb_purge_batch_size、启用独立undo表空间截断。

直接杀掉长事务不能立刻释放undo空间,必须等purge线程清理完历史版本,再配合表空间轮换和截断才能真正回收磁盘。
怎么快速定位拖垮purge的长事务
History list length持续不降,说明最老的那个活跃事务在钉住所有旧版本。别猜,用这条语句直接捞出真凶:
SELECT trx_id, trx_state, trx_started, TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS duration_sec, trx_mysql_thread_id, trx_query FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 600;
- 重点关注
trx_state = 'RUNNING'且trx_query IS NULL:这是连接空闲但事务没提交,99%是应用漏了COMMIT或连接池未 close -
trx_rows_modified > 10000且duration_sec > 300的 UPDATE/DELETE 必须立刻干预 - 用
trx_mysql_thread_id关联information_schema.PROCESSLIST,确认来源 IP 和用户,避免误杀
KILL前必须分状态判断,否则可能更糟
盲目 KILL 不仅无效,还可能让实例雪崩。不同状态要区别对待:
-
trx_state = 'RUNNING'且trx_query IS NULL:可安全KILL,大概率是连接泄漏 -
trx_state = 'LOCK WAIT':先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游事务 -
trx_state = 'ROLLING BACK':千万别动,此时KILL会让回滚从同步变异步,耗时翻倍、IO 更爆 - 批量
KILL必须加SLEEP(0.2)间隔执行,否则 purge 线程瞬间被压垮
杀完事务后,怎么让purge跟上并触发undo截断
杀掉源头只是第一步,History list length 不会立刻下降。必须主动助推 purge,并满足截断前提:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 检查
SHOW ENGINE INNODB STATUS\G中PURGE DONE for trx's n:o是否在推进;若停滞,说明 purge 线程本身被拖慢(比如磁盘 IO 饱和) - 临时加大清理能力:
SET GLOBAL innodb_purge_batch_size = 10000(默认 300) - 确保至少有 4 个 undo 表空间:
SHOW VARIABLES LIKE 'innodb_undo_tablespaces',值必须 ≥ 4;若只有 2 个,默认无法轮换 - 新增第 3 个:
CREATE UNDO TABLESPACE undo_003 ADD DATAFILE '/var/lib/mysql/undo_003.ibu' - 设旧的为 inactive:
ALTER UNDO TABLESPACE undo_001 SET INACTIVE;等Innodb_history_list_length显著回落(比如从 200 万降到 50 万以下),再执行ALTER UNDO TABLESPACE undo_001 TRUNCATE
为什么只调参(如innodb_max_purge_lag)完全无效
innodb_max_purge_lag 是节流阀,不是清洁工。它只在未 purge undo 超限时插入微秒级延迟,给 purge 线程腾资源,对已堆积的 history list length 毫无作用。
- 设成
0不是“关闭限流”,而是禁用保护,undo 持续膨胀直到磁盘满 - 设得过小(如 10000)会导致正常批量导入也被频繁 throttle,TPS 断崖下跌
- 真正起效的前提:先干掉那个
trx_state = 'RUNNING'且trx_query IS NULL的事务;它不释放 ReadView,所有旧版本 undo 全被钉死
整个流程必须按顺序执行:终止源头 → 新增 undo 表空间 → 设旧为 inactive → 等 purge 推进 → TRUNCATE。跳过任一环节,或试图手动删 undo_001.ibu 文件,都会失败甚至导致实例无法启动。










