MySQL 死锁日志里的锁类型和索引名怎么对应到 SQL
MySQL 死锁日志里的 index 不是 SQL 文本中的表别名,lock mode 也不是“某条 SQL 的类型”。正确的对应方式是:先用事务 ID 找到正在执行的语句,再用表名和索引名判断 InnoDB 锁住了哪棵索引,最后用 lock_data 对照 WHERE 条件和主键值。这样才能知道是两条 SQL 访问顺序相反,还是范围锁把相邻记录也纳入了等待。
看到 RECORD LOCKS ... index PRIMARY 时,先把它理解为“某张表的聚簇索引记录锁”;看到二级索引名时,要同时考虑该索引记录后附带的主键值。死锁诊断的重点不是逐字翻译日志,而是还原“谁持有什么、谁还要什么”。
SHOW ENGINE INNODB STATUS主要看最近一次死锁;频繁问题可打开innodb_print_all_deadlocks记录全部事件。INDEX_NAME指向锁所在索引,LOCK_TYPE区分 TABLE/RECORD,LOCK_STATUS区分 GRANTED/WAITING。- 二级索引锁的记录值通常还带主键;不要只凭索引名猜 SQL,必须结合事务语句、索引定义和执行条件。
先把日志字段翻译成锁对象
InnoDB 一行死锁记录通常同时出现表、索引、锁模式和记录值。表名回答“锁在哪张表”,索引名回答“通过哪棵索引定位到锁记录”,锁类型和状态回答“这是表级资源还是记录级资源、当前已持有还是正在等待”。例如 index PRIMARY 表示聚簇索引;index idx_account_status 则表示访问路径落在二级索引上。
| 字段 | 怎么理解 | 回到 SQL 时看什么 |
|---|---|---|
| TABLE / RECORD | 表级或记录级锁 | 是否由 DDL、LOCK TABLES 或行修改触发 |
| PRIMARY / 二级索引名 | 锁所在的索引 | 索引列顺序、是否覆盖 WHERE 条件 |
| S、X、IS、IX、GAP | 共享、排他、意向或间隙相关模式 | SELECT 加锁方式、UPDATE/DELETE 和范围条件 |
| GRANTED / WAITING | 已持有或正在等待 | 把等待资源连到另一事务持有的同一资源 |
| LOCK_DATA | 索引记录值或间隙标识 | 主键、二级索引列和 WHERE 的具体值 |

用最近一次死锁记录锁定两条 SQL
先执行下面的语句。它只展示最近一次 InnoDB 用户事务死锁,输出中的 TRANSACTION、WAITING FOR THIS LOCK、HOLDS THE LOCK(S) 和 WE ROLL BACK TRANSACTION 是诊断主线。
-- 读取最近一次 InnoDB 死锁摘要,不修改事务数据 SHOW ENGINE INNODB STATUS\G
把每个事务分成两列记录:已持有的资源、正在等待的资源。若事务 A 持有 orders.PRIMARY 的某条记录,同时等待 payments.PRIMARY;事务 B 的方向相反,就已经得到典型的交叉等待。日志里的 SQL 是当时正在执行的语句,但它不一定包含完整业务参数,所以还要用连接线程、应用日志或请求 ID补全实际值。
如果现场经常发生,临时打开全部死锁记录:
-- 仅在排查期打开,便于从错误日志收集每一次死锁 SET GLOBAL innodb_print_all_deadlocks = ON; -- 排查结束后关闭,避免长期增加日志噪声 SET GLOBAL innodb_print_all_deadlocks = OFF;
用 data_locks 把索引名和记录值补齐
死锁发生前后,Performance Schema 的锁表更适合看结构化字段。data_locks 同时包含已授予和等待中的数据锁;INDEX_NAME、LOCK_MODE、LOCK_STATUS 与 LOCK_DATA 正好对应日志中最容易误读的部分。
-- 先按事务、表和索引缩小范围,再看记录与状态
SELECT ENGINE_TRANSACTION_ID,
OBJECT_SCHEMA,
OBJECT_NAME,
INDEX_NAME,
LOCK_TYPE,
LOCK_MODE,
LOCK_STATUS,
LOCK_DATA
FROM performance_schema.data_locks
WHERE OBJECT_SCHEMA = 'shop'
AND OBJECT_NAME IN ('orders', 'payments')
ORDER BY ENGINE_TRANSACTION_ID, OBJECT_NAME, INDEX_NAME;
-- 查看谁持有锁、谁在等待该锁
SELECT requesting_engine_transaction_id,
blocking_engine_transaction_id,
requesting_engine_lock_id,
blocking_engine_lock_id
FROM performance_schema.data_lock_waits;
这里有三个关键边界。第一,表级意向锁的 INDEX_NAME 和 LOCK_DATA 可能为空,不要把它当成缺失索引。第二,二级索引记录的 LOCK_DATA 通常包含二级索引值并附带主键,用主键回表确认具体行。第三,supremum pseudo-record 表示索引页上的特殊上界记录,常见于范围或间隙相关诊断,不能当成业务主键。

从索引记录回到 SQL,修正访问顺序
拿到索引名后先查索引定义,而不是直接改隔离级别。假设日志指向 idx_account_status,就检查它的列顺序是否覆盖了业务条件:
-- 查看索引列顺序,确认日志中的索引如何匹配条件 SHOW CREATE TABLE orders\G -- 只取需要加锁的行,保持两个事务使用同一访问顺序 START TRANSACTION; SELECT id, status FROM orders WHERE account_id = 42 AND status = 'pending' FOR UPDATE; -- 业务更新完成后再提交,避免长时间占锁 COMMIT;
常见修复是让多个事务按相同顺序访问多张表或多个范围、缩短事务持续时间、为 UPDATE 和 SELECT ... FOR UPDATE 的条件建立合适索引,并在应用层对死锁回滚做有限次数重试。隔离级别会影响读操作的可见性,但不能把“死锁只靠调低隔离级别解决”当成结论;真正要复查的是锁定范围、索引路径和事务顺序。
常见问题
日志里的索引名就是 SQL 使用的唯一索引吗?
不一定。它表示 InnoDB 记录锁所在的索引;没有显式主键时也可能看到内部聚簇索引。应结合 SHOW CREATE TABLE 和执行计划确认访问路径。
为什么 LOCK_DATA 会是 NULL?
表级锁本来没有记录值;记录页不在缓冲池时,InnoDB 也可能不为诊断重新读盘。NULL 不能单独证明没有锁住具体行。
遇到死锁只要把 innodb_lock_wait_timeout 调大吗?
不建议。死锁检测开启时 InnoDB 会回滚一个事务,应用仍应捕获回滚并有限重试;应先修正事务顺序和锁定范围。
相关依据
字段含义可查阅 MySQL 8.4 的data_locks 表说明和Performance Schema 锁表概览;死锁诊断与处理可查阅InnoDB Deadlocks、How to Minimize and Handle Deadlocks。生产环境修改全局变量前,应结合日志保留策略和权限范围安排排查窗口。
Go os/exec 执行外部命令时怎么安全传递带空格参数
- 上一篇
- Go os/exec 执行外部命令时怎么安全传递带空格参数
- 下一篇
- Go recover 在 defer 中返回后 named result 如何避免静默成功
-
- 数据库 · MySQL | 2小时前 |
- MySQL ROW_NUMBER 去重后怎么保留完整原始行
- 416浏览 收藏
-
- 数据库 · MySQL | 3小时前 |
- MySQL 窗口函数怎么给每组记录编号后分页
- 395浏览 收藏
-
- 数据库 · MySQL | 5小时前 | MySQL · JSON_TABLE · JSON_EXTRACT · mysql JSON_TABLE JSON路径
- MySQL JSON 路径不存在时怎么区分 NULL 和空数组
- 209浏览 收藏
-
- 数据库 · MySQL | 6小时前 | MySQL · JSON · SQL 查询 · 数据展开 · mysql JSON_TABLE ON EMPTY ON ERROR JSON 数组 NESTED PATH
- MySQL JSON_TABLE 怎么把嵌套数组展开成行
- 296浏览 收藏
-
- 数据库 · MySQL | 9小时前 |
- MySQL 组合索引列顺序怎么配合范围条件和排序
- 385浏览 收藏
-
- 数据库 · MySQL | 15小时前 | MySQL · binlog · 备份恢复 · mysql binary log 备份恢复 mysqlbinlog 二进制日志
- MySQL 备份恢复时如何验证二进制日志位置
- 216浏览 收藏
-
- 数据库 · MySQL | 16小时前 |
- MySQL LOAD DATA 导入带引号换行的 CSV 怎么设置
- 335浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 19次使用
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 177次使用
-
- C-Eval
- 深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
- 111次使用
-
- AI Prompt Library
- 探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
- 38次使用
-
- Generrated
- Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
- 18次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- golang 基于 mysql 简单实现分布式读写锁
- 2023-01-07 384浏览
-
- 详解如何利用GORM实现MySQL事务
- 2023-01-07 184浏览
-
- Go语言实现操作MySQL的基础知识总结
- 2023-01-23 265浏览

