
index_merge导致死锁案例分析
事务1和事务2未被放置在事务中执行 **事务1执行的 **事务2持有 **因使用 3.2 模拟
发布日期:2021-05-18 09:16:21
浏览次数:18
分类:精选文章
本文共 2462 字,大约阅读时间需要 8 分钟。
一、死锁现象描述
1.1 基本环境信息
数据库版本:5.7.26-log
隔离级别:READ-COMMITTED2.0 死锁表结构信息
表名:deadlock_test
CREATE TABLE `deadlock_test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `info_uuid` varchar(50) DEFAULT NULL, `view_date` date DEFAULT NULL, `view_count` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_view_date` (`view_date`), KEY `idx_info_uuid` (`info_uuid`)) ENGINE=InnoDB AUTO_INCREMENT=908189 DEFAULT CHARSET=utf8
3.0 死锁日志
死锁发生时间:2020-05-14 07:25:04
死锁原因:- 事务1(线程2557156)执行更新操作,等待
deadlock_test
表的PRIMARY
索引上的锁。 - 事务2(线程2557158)持有
deadlock_test
表的PRIMARY
索引上的锁,并等待idx_view_date
索引上的锁。
二、原因分析
2.1 死锁日志分析
2.1.1 事务1
- 业务SQL:
UPDATE deadlock_test SET VIEW_COUNT = VIEW_COUNT + 1 WHERE INFO_UUID = '1a973b987d1d11eaa8c07cd30ad3aa18' AND VIEW_DATE = '2020-05-14'
- 锁等待:
- 等待
deadlock_test
表的PRIMARY
索引上的锁,涉及记录id=900004
。
- 等待
- MySQL处理方案:
- 回滚事务。
2.1.2 事务2
- 业务SQL:
UPDATE deadlock_test SET VIEW_COUNT = VIEW_COUNT + 1 WHERE INFO_UUID = '27c3cf1e63fa11ea8b9a7cd30ae0074a' AND VIEW_DATE = '2020-05-14'
- 锁持有:
- 持有
deadlock_test
表的PRIMARY
索引上的锁,涉及记录id=900004
。
- 持有
- 锁等待:
- 等待
deadlock_test
表的idx_view_date
索引上的锁,涉及记录view_date='2020-05-14', id=900004
。
- 等待
- MySQL处理方案:
- 不回滚,执行成功。
2.2 发生死锁SQL以及数据分布分析
2.2.1 业务SQL执行计划
- 查询使用
index_merge
策略,分别使用idx_info_uuid
和idx_view_date
索引,取交集进行查询。
2.2.2 业务SQL数据分布
INFO_UUID
字段的过滤性较好,但仍需使用单列索引idx_info_uuid
和idx_view_date
进行index_merge
。- 此外,通过数据分布可知,
INFO_UUID
和VIEW_DATE
字段能够有效约束数据范围,定位到特定记录。
2.3 初步的分析判断
UPDATE
语句试图修改的记录为id=900006
,但死锁日志中却发现其试图等待id=900004
的锁。异常。id=900004
的锁,但仍需等待view_date='2020-05-14'
和id=900004
的锁。异常。index_merge
,MySQL在执行过程中可能对idx_info_uuid
和idx_view_date
进行扫描加锁,扩大了锁范围,导致并发请求时发生死锁。可能原因。三、测试验证
3.1 数据准备
- 表
deadlock_test
已准备好测试数据,确保当INFO_UUID
和VIEW_DATE
组合唯一时,可以正确定位到目标记录。
3.2 模拟index_merge
下的加锁情况
- 会话A和会话B同时执行查询时,可能导致
index_merge
下的锁等待,进一步触发死锁。 | 模拟SQL | 会话 | 结果 | |--------|-------|------| | UPDATE ... FOR UPDATE | 会话A | 成功 | | UPDATE ... FOR UPDATE | 会话B | 死锁 |
3.3 死锁日志查看
- 从
information_schema
中获取锁等待信息,确认两个会话相互等待对方的锁资源,形成死锁闭环。
3.4 锁等待分析
- 会话A和会话B之间的锁等待关系:
- 会话A等待会话B持有的锁,
- 会话B等待会话A持有的锁。
- MySQL的死锁检测在启用时会自动回滚资源较少的事务,防止死锁。关闭
innodb_deadlock_detect
可能会导致锁等待信息未被记录。
3.5 整体分析处理
- 案例分析
- 会话A和会话B在执行
index_merge
下的并发读取时,由于锁资源扩大,导致彼此等待。
- 会话A和会话B在执行
- 处理方法
- 优化索引:将
idx_info_uuid
和idx_view_date
合并为一个复合索引,以减少锁等待。 - 优化查询:修改查询方式,避免使用
index_merge
,而是利用-coverging index(覆盖索引)或其他高效索引策略。 - 锁管理:使用合适的锁模式(如
MySQL
的隐式锁或显式锁),减少锁的竞争程度。 - 事务设计:将多个数据操作合并到一个事务中,减少并发锁请求的次数。
- 优化索引:将
四、总结
此死锁事件的成因在于数据库查询策略中对索引的使用不当,导致锁资源扩大。index_merge
策略和单字段索引的结合,引发了多个锁的等待,最终导致死锁。我建议优化索引结构,减少锁等待,采用合适的查询策略,确保在高并发环境下系统的稳定性和性能。
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2025年04月19日 21时44分46秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
map[]和map.at()取值之间的区别
2019-03-08
VTK:可视化之RandomProbe
2019-03-09
Java时间
2019-03-09
【编程】C语言入门:1到 100 的所有整数中出现多少个数字9
2019-03-09
pair的用法
2019-03-09
javaWeb服务详解(含源代码,测试通过,注释) ——Emp的Dao层
2019-03-11
echarts 基本图表开发小结
2019-03-11
TreeSet、TreeMap
2019-03-11
JVM内存模型
2019-03-11
可变长度参数
2019-03-11
GitHub上传时,项目在已有文档时直接push出现错误解决方案
2019-03-11
嵌入式系统试题库(CSU)
2019-03-12
00010.02最基础客户信息管理软件(意义类的小项目,练习基础,不涉及数据库)
2019-03-12
00013.05 字符串比较
2019-03-12
UE4 错误列表 error码(只记录我遇到的情况,持续添加,未完成)
2019-03-13
Android 架构组件 – 让天下没有难做的 App
2019-03-13
能解决数据可视化大屏需求的3款可视化工具
2019-03-13
第01问:MySQL 一次 insert 刷几次盘?
2019-03-13