应直接查INFORMATION_SCHEMA.INNODB_TRX而非SHOW PROCESSLIST,因后者仅显示连接状态,90%阻塞型长事务藏在Command='Sleep'、State=NULL但TRX_STATE='RUNNING'的“假空闲”连接里,真正持锁卡住DDL或核心业务的必须靠INNODB_TRX定位。

为什么 SHOW PROCESSLIST 找不到真卡住的事务
因为 90% 的阻塞型长事务根本不会出现在 SHOW PROCESSLIST 的活跃列表里——它们状态是 Command = 'Sleep'、State = NULL、INFO 为空,看起来像空闲连接,但 INFORMATION_SCHEMA.INNODB_TRX 里 TRX_STATE = 'RUNNING',且 TRX_STARTED 已过去几分钟甚至几小时。这种“假空闲”连接正持着行锁、MDL 锁或事务级资源,卡住 DDL 或其他关键查询。
只查 PROCESSLIST 就动手,等于闭眼开枪:要么杀错(杀的是只读连接),要么杀晚(真正持锁的线程根本没露头)。
必须用 INNODB_TRX 定位 + 计算真实运行时长
INFORMATION_SCHEMA.INNODB_TRX 才是唯一可信来源。重点盯这三列:
-
TRX_STARTED:事务真实开始时间,用TIMESTAMPDIFF(SECOND, TRX_STARTED, NOW())算秒数——别信PROCESSLIST.TIME,它只计连接空闲/执行时间,和事务生命周期无关 -
TRX_STATE = 'RUNNING':说明事务既没提交也没回滚,资源仍在占用中 -
TRX_MYSQL_THREAD_ID:这才是KILL的目标 ID;它和PROCESSLIST.ID可能不一致,尤其在连接复用场景下
生产建议阈值设为 30 秒而非 10 分钟:WHERE TRX_STATE = 'RUNNING' AND TIMESTAMPDIFF(SECOND, TRX_STARTED, NOW()) > 30。长时间未提交的事务,大概率已异常,不是业务合理行为。
KILL CONNECTION 还是 KILL QUERY?看状态,不看直觉
选错命令等于白干:
- 如果
TRX_STATE = 'RUNNING'且PROCESSLIST.STATE是Waiting for table metadata lock、Locked或长期Sleep→ 必须用KILL CONNECTIONthread_id - 如果线程当前确实在跑一个慢
SELECT或UPDATE,且应用依赖连接复用(如 HikariCP)→ 可先试KILL QUERYthread_id,3 秒内状态没变回Sleep,立刻升级为KILL CONNECTION - 严禁对
TRX_WAITING_TRX_ID IS NOT NULL的等待方执行KILL CONNECTION——这会让持锁者继续跑,堵得更死
KILL QUERY 只停语句,事务不结束,锁不释放;KILL CONNECTION 才触发强制回滚并释放所有锁。MySQL 5.7+ 中,KILL id 等价于 KILL CONNECTION id,但显式写全更安全、可读。
KILL 后锁还在?不是失败,是回滚在后台跑
执行 KILL CONNECTION 后,SHOW PROCESSLIST 显示状态为 Killed 是正常现象。InnoDB 回滚耗时 ≈ 正向操作的 3~5 倍:
- 几行更新:通常 100ms 内完成
- 百万行
UPDATE:可能卡在Rolling back状态数分钟,期间锁仍被占用
务必再查 INNODB_TRX 中该事务的 TRX_OPERATION_STATE 是否为 rolling back,并结合 TRX_ROWS_MODIFIED 估算剩余工作量。最易被忽略的一点:kill 后必须立刻验证 INNODB_TRX 是否清空,而不是只看 PROCESSLIST 里有没有那个 ID——线程 ID 可能被复用,而事务残留会导致后续 ALTER TABLE、TRUNCATE 持续阻塞。











