必须查INNODB_TRX表按trx_started筛选超600秒的事务,重点识别trx_state='RUNNING'且trx_query IS NULL的空闲事务,再关联PROCESSLIST确认来源后分类KILL。

怎么查出真正卡住 purge 的长事务
别信 SHOW PROCESSLIST 的 Time 字段——它只算当前语句执行时长,和事务开启时间完全无关。真正钉死 undo 的,是那些早已空闲、没执行任何 SQL、却迟迟不提交的连接。
必须查 INFORMATION_SCHEMA.INNODB_TRX 表,按 trx_started 排序找最老的:
SELECT trx_id, trx_started, trx_state, trx_rows_modified, trx_mysql_thread_id, SUBSTRING(trx_query, 1, 80) AS trx_query_truncated FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 600 ORDER BY trx_started LIMIT 5;
-
trx_state = 'RUNNING'且trx_query IS NULL:99% 是应用崩溃后连接残留,或 ORM 开了事务但漏了commit/rollback,最危险 -
trx_rows_modified > 10000且持续超 300 秒:大事务已卡住,比如未分页的批量更新,需立刻干预 -
trx_rows_modified = 0的只读事务也会阻塞 purge,但危害小,可暂缓处理
拿到 trx_mysql_thread_id 后,用它 JOIN information_schema.PROCESSLIST 查 HOST、USER、INFO,确认是不是异常挂起的 Python 或 Java 进程。
kill 前为什么必须看 trx_state
盲目 KILL 不仅无效,还可能让实例雪崩。不同状态对应完全不同的处理逻辑:
-
trx_state = 'RUNNING'且trx_query IS NULL:可安全KILL对应线程,基本是连接泄漏,不杀它 purge 就永远卡死 -
trx_state = 'LOCK WAIT':它被别的事务堵住了,先查INNODB_LOCK_WAITS找出blocking_trx_id,优先干掉上游事务 -
trx_state = 'ROLLING BACK':千万别动!此时 InnoDB 正在同步回滚,KILL会让回滚变异步,IO 更爆、purge 更慢,甚至拖垮整个清理链
若 trx_rows_modified > 100000,回滚可能持续数分钟;若 History list length > 10000,批量 KILL 必须加 SLEEP(0.2) 间隔执行,否则磁盘 IO 会瞬间打满。
杀完之后 History list length 为什么还不降
杀掉源头事务后,History list length 不会立刻下降——purge 线程还在慢慢扫,旧 undo 段还占着空间。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
先确认 purge 是否真在推进:
SHOW ENGINE INNODB STATUS\G
关注 “PURGE DONE for trx's n:o ” 行,对比刚杀掉的 <code>trx_id 是否已被覆盖。
- 临时加大单次清理量:
SET GLOBAL innodb_purge_batch_size = 10000(默认 300) - 提高 purge 频率:
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1(默认 128,值越小越激进) - 确保
innodb_undo_log_truncate = ON,且innodb_undo_tablespaces >= 4(仅 ≥2 不够轮换)
注意:ALTER UNDO TABLESPACE ... TRUNCATE 不是“清空按钮”,它只在 purge 跟上、无活跃依赖、且至少有 2 个 active undo 表空间时才生效。
为什么调参不能替代 kill 长事务
innodb_max_purge_lag 是节流阀,不是清洁工——它只在未 purge undo 超限时给写入踩刹车,对已堆积的 History list length 完全无效。
同样,innodb_purge_batch_size 再大、innodb_max_undo_log_size 再小,也扛不住一个运行 2 小时的 trx_state = 'RUNNING' 且 trx_query IS NULL 的事务。它会把所有早于该事务快照的 undo 全部钉死,导致 purge 彻底失能。
真正根治点不在参数,而在应用层:必须推动业务修复连接池未 close、ORM 事务未 commit、HTTP 请求超时后未 rollback 等逻辑漏洞。运维能做的,只是把那个最老的 trx_id 找出来、分状态干掉、再助推 purge 走完最后一公里。

















