MySQL 死锁日志只看三行:谁持锁、谁在等、等哪条索引

举报
yd_216394844 发表于 2026/10/27 12:00:52 2026/10/27
【摘要】 SHOW ENGINE INNODB STATUS 输出的 LATEST DETECTED DEADLOCK 段落动辄四五十行,真正有用的只有三处:TRANSACTION 段落里的 lock_mode 与持锁索引、WAITING 那行的 waiting for this lock to be granted、以及两边 SQL 的最后一句。先看「谁持谁等」。死锁日志里会有 TRANSACTIO...

SHOW ENGINE INNODB STATUS 输出的 LATEST DETECTED DEADLOCK 段落动辄四五十行,真正有用的只有三处:TRANSACTION 段落里的 lock_mode 与持锁索引、WAITING 那行的 waiting for this lock to be granted、以及两边 SQL 的最后一句。

先看「谁持谁等」。死锁日志里会有 TRANSACTION 1 和 TRANSACTION 2,某个标注 HOLDS THE LOCK(S),另一个标注 WAITING FOR THIS LOCK。持锁的一方是既得利益者,等锁的一方是被回滚的,InnoDB 会选择代价小的那个回滚,通常是修改行数少的。

再看锁类型。lock_mode X locks rec but not gap 是行锁,说明命中了唯一索引或主键;locks gap before rec 是间隙锁,说明用了范围条件或非唯一索引。看到 gap 锁基本可以断定:RR 隔离级别下,两个事务用了不同的索引顺序去做范围更新。经典场景是先按 A 索引更新一批,再按 B 索引更新另一批,另一个事务反过来。解法统一是让两条路径的加锁顺序一致,或者把事务拆小,别在一个事务里跨多张表乱序更新。

第三看索引。日志里 INDEX_NAME 和 lock id 会指出锁在哪个索引的哪条记录上。如果 INDEX_NAME 是 PRIMARY,说明走的是主键;如果是二级索引名,就要怀疑这条 SQL 没走预期索引,或者优化器选了另一个。加锁范围超出预期是最常见的死锁根源,用 EXPLAIN 确认实际走的索引,必要时 FORCE INDEX。

几个高频误区。一是以为加了唯一索引就不会有间隙锁,范围查询照样有。二是以为读不加锁,RR 下的快照读确实不加,但 SELECT ... FOR UPDATE 和 UPDATE 都加。三是以为重试三次能解决,死锁是设计问题,重试只是把概率往下压,压不到零。

线上处置顺序:先 SHOW ENGINE INNODB STATUS 抓现场,再 SHOW PROCESSLIST 看有没有长事务,然后 INNODB_TRX 里查 trx_started 最早的那个。长事务是死锁的温床,超过十秒的事务在高峰期就该告警。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。