
怎么看 INNODB STATUS 里的死锁信息
MySQL 的死锁信息不会单独存成日志文件,默认只藏在 SHOW ENGINE INNODB STATUS 输出里,而且每发生一次死锁,它只保留最近一次的完整记录。想确认是不是真有死锁,不能只看错误码 Deadlock found when trying to get lock,得亲手翻这个输出。
执行命令:
SHOW ENGINE INNODB STATUS\G注意加
\G,否则事务列表会挤成一行很难读。
关键段落是 LATEST DETECTED DEADLOCK,它下面会列出两个(或多个)事务各自的 SQL、持有的锁、等待的锁、事务 ID、线程 ID,甚至锁住的具体 PRIMARY 或二级索引记录。
- 如果没看到这段,说明最近没触发死锁,或者被后续的其他 INNODB STATUS 查询覆盖了
- 该输出是快照,不是实时流;重启 MySQL 后清空
- 部分云数据库(如阿里云 RDS)默认关闭此功能,需手动开启
innodb_status_output_locks
为什么 SHOW ENGINE INNODB STATUS 看不到死锁细节
最常见原因是 innodb_status_output_locks 变量关着——它控制是否在 INNODB STATUS 中打印锁信息。没有锁的详细路径和模式(如 X 锁 vs S 锁),根本没法判断谁持有什么、谁在等什么。
检查当前值:
SELECT @@innodb_status_output_locks;返回
0 就得开:SET GLOBAL innodb_status_output_locks = 1;
- 该变量仅影响
SHOW ENGINE INNODB STATUS,不影响死锁检测本身 - 5.6+ 才支持;低于此版本即使开了也看不到锁粒度细节
- 开启后 STATUS 输出体积明显变大,但对性能几乎无影响
从死锁日志反推哪条 SQL 招来的麻烦
INNODB STATUS 里每个事务块开头都标着 TRANSACTION xxx, ACTIVE xxx sec,后面紧跟着 mysql tables in use x, locked x,再下面是 LOCK WAIT 或 HOLDS THE LOCK(S)。重点看三处:
-
UPDATE/DELETE ... WHERE那行 SQL —— 往往就是问题语句,尤其带非主键条件、范围扫描、没走索引的 -
Record lock on index `xxx` of table `db`.`tbl`—— 锁在哪张表哪个索引上,结合执行计划看是否扫了太多行 -
Waiting for this lock to be granted后面的锁类型和记录值,比如supremum pseudo-record常意味着间隙锁冲突
注意:显示的 SQL 是事务中最后执行的那条,不一定是真正申请锁的第一条;如果用了 ORM,还得对照实际生成的语句和事务边界。
死锁日志里出现 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: 却没看到对应事务
这是典型的时间差问题:死锁发生时两个事务都在跑,但当你执行 SHOW ENGINE INNODB STATUS 时,其中一个可能已经回滚或提交完毕,STATUS 只保留“幸存者”的上下文,另一方只剩半截痕迹。
此时要交叉验证:
- 查
information_schema.INNODB_TRX看当前活跃事务,比对TRX_ID和 STATUS 里的 ID 是否匹配 - 开慢查询日志 +
log_output = 'TABLE',配合start_time和sql_text定位相近时间点的可疑语句 - 用
performance_schema.data_locks(8.0+)实时看谁持有哪些锁,比 STATUS 更及时
别指望 STATUS 给你拼出完整时间线——它只是个事故快照,不是黑匣子。










