真正有用的锁等待信息藏在 transactions 小节末尾的 ---transaction ... waiting for this lock to be granted--- 块里,需用 \g 格式查看并搜索该关键字定位事务、sql、锁类型及等待时长,结合 information_schema 表实时关联等待关系与线程 id。

SHOW ENGINE INNODB STATUS 输出里哪部分看锁等待
真正有用的锁等待信息藏在 TRANSACTIONS 小节末尾的 ---TRANSACTION ... WAITING FOR THIS LOCK TO BE GRANTED--- 块里,不是开头的 LATEST DETECTED DEADLOCK。很多人扫一眼就跳过,结果漏掉关键等待链。
实操建议:
- 执行
SHOW ENGINE INNODB STATUS\G(注意加\G,否则输出挤成一团) - 用
Ctrl+F搜WAITING FOR THIS LOCK TO BE GRANTED,定位到最近一次等待 - 往上翻几行,找到对应的
TRANSACTIONID 和它正在执行的 SQL(mysql tables in use或Trx has been waiting上方那条INSERT/UPDATE/SELECT...) - 往下看同一事务块里的
lock_mode X locks rec but not gap waiting这类描述,确认锁类型和粒度
为什么 SHOW ENGINE 看到的锁信息常“对不上”实际 SQL
因为 SHOW ENGINE INNODB STATUS 记录的是 *当前快照*,而锁可能在你执行命令前 1 秒就释放了——尤其是短事务。更常见的是:你看到的等待事务,它的 SQL 已经执行完,但事务没提交,锁还挂着。
实操建议:
- 别单次执行,改用循环观察:
watch -n 0.5 'mysql -e "SHOW ENGINE INNODB STATUS\G" | grep -A 10 "WAITING FOR THIS LOCK"' - 重点看
Trx has been waiting 12 sec这种时间戳,大于 2 秒的才值得追 - 如果
lock_mode S(共享锁)在等lock_mode X(排他锁),基本能确定是读写冲突;若两个都是X,大概率是更新同一行引发的互等
如何关联锁等待和具体表、行(包括隐藏主键)
SHOW ENGINE 不直接显示表名和行值,只给 TABLE: `db`.`t1` 和一串十六进制的 RECORD LOCKS space id ... page no ... n bits。真正要定位到哪一行,得靠 page no + space id 反查。
实操建议:
- 先用
SELECT TABLE_ID, NAME FROM INFORMATION_SCHEMA.INNODB_TABLES WHERE NAME = 'db/t1';确认space id对应的表 - 拿到
page no后,查INFORMATION_SCHEMA.INNODB_BUFFER_PAGE(需开启innodb_buffer_page监控,5.7+ 默认关闭) - 更实用的办法:从等待事务的 SQL 入手。比如看到
UPDATE t1 SET x=1 WHERE id=123在等,就直接SELECT * FROM t1 WHERE id=123 FOR UPDATE;看是否卡住——这比解析 page 更快 - 注意:如果表没显式主键,InnoDB 会用隐式
ROW_ID,此时RECORD LOCKS显示的可能是supremum pseudo-record,说明锁在间隙上
替代方案:information_schema.innodb_trx + innodb_lock_waits 更稳定
SHOW ENGINE 是文本快照,有延迟且难解析;而 INFORMATION_SCHEMA 表是实时视图,适合脚本化排查。但要注意:它们不包含锁的具体记录位置(如哪一行),只告诉你谁在等谁。
实操建议:
- 查等待关系:
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;,重点关注BLOCKING_TRX_ID和REQUESTING_TRX_ID - 关联事务详情:
SELECT trx_id, trx_mysql_thread_id, trx_query FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_id IN ('xxx','yyy'); - 线程 ID 能直接杀:比如
KILL 12345;(对应trx_mysql_thread_id) - 风险点:MySQL 8.0.26+ 中,
INNODB_LOCK_WAITS的字段名从blocking_trx_id改为BLOCKING_TRX_ID(全大写),旧脚本会报错
锁等待的复杂性不在命令怎么敲,而在「谁持有了什么锁却迟迟不释放」——可能是长事务、未提交的 autocommit=0 会话,甚至是一个被遗忘的交互式连接。盯住 Trx has been waiting 的秒数,比死记日志格式有用得多。











