查information_schema.innodb_trx可快速定位阻塞事务,重点关注trx_mysql_thread_id、trx_state、trx_started和trx_waiting_trx_id;再结合show processlist和innodb_lock_waits分析锁链,kill前须确认业务上下文并优先用kill query。

查 information_schema.INNODB_TRX 看谁在堵着
锁表问题本质是事务没提交或卡住了,得先揪出那个“赖着不走”的事务。直接查 information_schema.INNODB_TRX 是最快路径,它实时反映当前活跃事务。
-
TRX_ID和TRX_MYSQL_THREAD_ID是关键:后者能对应到PROCESSLIST里的线程 ID -
TRX_STATE为LOCK WAIT表示正在等锁;RUNNING但TRX_STARTED时间很早,大概率是长事务没提交 -
TRX_QUERY字段不一定有值——如果事务只执行了BEGIN没跑 SQL,或者 SQL 已执行完但事务仍开着,这里就是NULL - 别只盯着
TRX_QUERY,要结合TRX_STARTED和TRX_WAITING_TRX_ID判断因果关系
用 SHOW PROCESSLIST 匹配线程与 SQL
查到可疑的 TRX_MYSQL_THREAD_ID 后,立刻执行 SHOW PROCESSLIST,找对应 ID 的那一行。这才是你真正能 kill 掉的入口。
-
Command列为Sleep且Time很大,说明应用拿了连接没关,事务可能还挂着 -
State是Locked或Updating但Time持续增长,SQL 本身可能卡在磁盘 I/O 或锁等待里 -
Info字段显示的是当前正在执行(或最后执行)的语句,但注意:它可能被截断,超长 SQL 看不全 - 如果
Info为空,不代表没在跑 SQL——可能是用了PDO::ATTR_EMULATE_PREPARES = true,实际语句藏在预处理逻辑里
抓 INNODB_LOCK_WAITS 和 INNODB_LOCKS 锁链关系
当多个事务互相等待时,单看一个事务看不出全貌。INNODB_LOCK_WAITS 是唯一能直观看到“谁在等谁”的系统视图。
-
WAITING_TRX_ID对应被堵住的事务,BLOCKING_TRX_ID对应持锁者,两字段直接构成锁等待链 -
INNODB_LOCKS能查到具体锁在哪张表、哪个索引、哪几行(LOCK_TRX_ID,LOCK_INDEX,LOCK_DATA),但LOCK_DATA只对主键有效,二级索引锁会显示索引值而非行数据 - MySQL 8.0+ 中
INNODB_LOCKS被移除了,改用performance_schema.data_locks,字段名和结构都变了,别硬套老文档 - 锁信息是瞬态的,脚本里查完要立刻存下来,否则再查可能就没了
避免误杀:kill 前确认事务上下文
看到长事务就 KILL?危险。很多业务逻辑依赖事务原子性,比如订单创建 + 库存扣减 + 日志写入,中间 KILL 可能导致状态不一致。
- 先用
SELECT * FROM performance_schema.threads WHERE THREAD_ID = ?查线程的PROCESSLIST_INFO和PROCESSLIST_DB,确认是不是核心业务库 - 检查应用日志或监控,看这个线程对应的请求是否还在重试、是否已超时——有时 kill 反而让下游更混乱
- 如果确定要 kill,优先用
KILL QUERY(只中断当前语句),而不是KILL(中断整个连接),给事务留出回滚机会 - 某些 ORM(如 Laravel Eloquent)在事务里执行失败后不会自动 rollback,而是等着下次 commit 或连接关闭才回滚,这种场景下
KILL后残留锁可能持续数秒
锁表排查不是拼手速,是比耐心和上下文理解。最常被忽略的是:你以为的“慢 SQL”可能根本没在跑,只是连接空挂着;而真正卡住的那条语句,可能早在 3 秒前就执行完了,现在只是事务没关。











