应立即执行show engine innodb status\g抓取latest detected deadlock快照,重点比对(1)(2)事务的holds the lock(s)与waiting for this lock to be granted,结合index名、heap no及lock_mode定位冲突索引与记录。

怎么看懂 SHOW ENGINE INNODB STATUS 里的死锁段落
MySQL 不会单独保存死锁日志,SHOW ENGINE INNODB STATUS 输出中只有最近一次死锁的完整上下文,且只保留 10 秒左右(受 innodb_print_all_deadlocks=OFF 默认限制)。关键不是“找日志”,而是立刻执行命令抓取当前快照。
执行后重点定位 *** (1) TRANSACTION: 和 *** (2) TRANSACTION: 开头的两个事务块,它们构成死锁闭环。每个事务块里:mysql tables in use 告诉你涉及哪些表,LOCK WAIT 行说明它卡在等哪个锁,WAITING FOR THIS LOCK TO BE GRANTED 后面跟着具体锁类型(如 record lock, heap no 5)和索引名(如 PRIMARY 或 idx_user_id)。
常见误读:把 Trx id 当成线程 ID —— 它是 InnoDB 内部事务号,要查 SQL 线程得结合 trx_mysql_thread_id 字段去 INFORMATION_SCHEMA.PROCESSLIST 关联。
为什么死锁信息里看不到完整的 SQL 语句
InnoDB 在死锁检测时只记录事务持有的锁、等待的锁和最后执行的语句(HELD THE LOCK(S) 和 WAITING FOR THIS LOCK TO BE GRANTED 上方的 INSERT/UPDATE/DELETE 行),但不会保存整个事务的 SQL 堆栈。如果事务包含多条语句,只显示最后一条触发锁冲突的那条。
- 若需完整 SQL,必须提前开启
slow_query_log并设置long_query_time=0,或使用performance_schema.events_statements_history_long查对应thread_id -
innodb_status_output_locks(8.0.17+)可增强锁信息粒度,但不补全 SQL - 应用层应在事务开头打日志,用唯一 trace_id 关联数据库操作
如何从锁信息反推哪行数据被堵住了
看 WAITING FOR THIS LOCK TO BE GRANTED 下的 lock_mode X locks rec but not gap waiting 这类描述,再结合 Record lock, heap no 5 和索引名,就能定位到具体记录。
例如:
RECORD LOCKS space id 123 page no 1024 n bits 72 index `PRIMARY` of table `test`.`t1` trx id 123456789 lock_mode X locks rec but not gap waiting Record lock, heap no 5 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
说明事务在主键索引上等待第 5 条物理记录(heap no 5)。此时可用:
-
SELECT * FROM test.t1 WHERE id = ?—— 如果是主键,直接用主键值查;否则需通过INFORMATION_SCHEMA.INNODB_BUFFER_PAGE或解析 ibd 文件(不推荐线上) - 用
SELECT * FROM test.t1 FORCE INDEX(`索引名`) WHERE ...模拟查询路径,验证是否走对索引 - 注意
heap no是页内偏移,不是主键值,不能直接当 ID 用
为什么反复执行 SHOW ENGINE INNODB STATUS 看不到新死锁
默认情况下,InnoDB 只记录最后一次死锁,且该记录会在下次死锁发生时被覆盖。除非你已启用 innodb_print_all_deadlocks=ON 并配置了错误日志输出路径(log_error),否则旧死锁信息无法回溯。
启用后,所有死锁都会追加写入 MySQL 错误日志(非 slow log),格式与 SHOW ENGINE 输出一致,但更稳定可靠:
- 修改配置文件:在
[mysqld]下添加innodb_print_all_deadlocks=ON - 无需重启,运行
SET GLOBAL innodb_print_all_deadlocks=ON;即可生效(但仅对后续死锁有效) - 注意错误日志体积增长,建议配合 logrotate 或定期归档
真正棘手的不是看不懂死锁,而是没在它发生的 10 秒窗口内执行命令,或者没开全量记录就以为“没死锁”——其实只是没看见。











