锁--07_2---- index merge(索引合并)引起的死锁
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 案例分析
- 生产背景
- 死锁日志
- 表结构
- 执行计划 EXPLAN
- 为什么会用 index_merge(索引合并)
- 为什么用了 index_merge就死锁了
- 解决方案
- 注:MySQL官方已经确认了此bug:==77209==
案例分析
生产背景
生产环境出现死锁流水,通过查看死锁日志,看到造成死锁的是两条一样的update语句(只有where条件中的值不同),如下:
UPDATE test_table SET `status` = 1 WHERE `trans_id` = 'xxx1' AND `status` = 0;
UPDATE test_table SET `status` = 1 WHERE `trans_id` = 'xxx2' AND `status` = 0;
一开始比较费解,通过大量查询跟学习后,分析出了死锁形成的具体原理,特分享给大家,希望能帮助到遇到同样问题的朋友。
死锁日志
*** (1) TRANSACTION:
TRANSACTION 791913819, ACTIVE 0 sec starting index read, thread declared inside InnoDB 4999
mysql tables in use 3, locked 3
LOCK WAIT 4 lock struct(s), heap size 1184, 3 row lock(s)
MySQL thread id 462005230, OS thread handle 0x7f55d5da3700, query id 2621313306 x.x.x.x test_user Searching rows for update
UPDATE test_table SET `status` = 1 WHERE `trans_id` = 'xxx1' AND `status` = 0;
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 110 page no 39167 n bits 1056 index `idx_status` of table `test`.`test_table` trx id 791913819 lock_mode X waiting
Record lock, heap no 495 PHYSICAL RECORD: n_fields 2; compact format; info bits 0*** (2) TRANSACTION:
TRANSACTION 791913818, ACTIVE 0 sec starting index read, thread declared inside InnoDB 4999
mysql tables in use 3, locked 3
5 lock struct(s), heap size 1184, 4 row lock(s)
MySQL thread id 462005231, OS thread handle 0x7f55cee63700, query id 2621313305 x.x.x.x test_user Searching rows for update
UPDATE test_table SET `status` = 1 WHERE `trans_id` = 'xxx2' AND `status` = 0;
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 110 page no 39167 n bits 1056 index `idx_status` of table `test`.`test_table` trx id 791913818 lock_mode X
Record lock, heap no 495 PHYSICAL RECORD: n_fields 2; compact format; info bits 0*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 110 page no 41569 n bits 88 index `PRIMARY` of table `test`.`test_table` trx id 791913818 lock_mode X locks rec but not gap waiting
Record lock, heap no 14 PHYSICAL RECORD: n_fields 30; compact format; info bits 0*** WE ROLL BACK TRANSACTION (1)
简要分析下上边的死锁日志:
1、第一块内容(第1行到第9行)中,第6行为事务(1)执行的SQL语句,第7和第8行意思为事务(1)在等待 idx_status 索引上的X锁;
2、第二块内容(第11行到第19行)中,第16行为事务(2)执行的SQL语句,第17和第18行意思为事务(2)持有 idx_status 索引上的X锁;
3、第三块内容(第21行到第23行)的意思为,事务(2)在等待 PRIMARY 索引上的X锁。(but not gap指不是间隙锁)
4、最后一句的意思即为,MySQL将事务(1)进行了回滚操作。
表结构
CREATE TABLE `test_table` (`id` int(11) NOT NULL AUTO_INCREMENT,`trans_id` varchar(21) NOT NULL,`status` int(11) NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `uniq_trans_id` (`trans_id`) USING BTREE,KEY `idx_status` (`status`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
- 主键索引: id
- 唯一索引: trans_id
- 普通索引 :status
InnoDB引擎中有两种索引:
聚簇索引: 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据。
辅助索引: 辅助索引叶子节点存储的是主键值,也就是聚簇索引的键值。
主键索引 PRIMARY 就是聚簇索引,叶子节点中会保存行数据。 uniq_trans_id 索引和 idx_status 索引为辅助索引,叶子节点中保存的是主键值,也就是id列值。
当我们通过辅助索引查找行数据时,先通过辅助索引找到主键id,再通过主键索引进行二次查找(也叫回表),最终找到行数据。
执行计划 EXPLAN

通过看执行计划,可以发现,update语句用到了index merge(索引合并),也就是这条语句既用到了 uniq_trans_id 索引,又用到了 idx_status 索引,
Using intersect(uniq_trans_id,idx_status) 的意思是通过两个索引获取交集。
为什么会用 index_merge(索引合并)
MySQL5.0之前,一个表一次只能使用一个索引,无法同时使用多个索引分别进行条件扫描。但是从5.1开始,引入了 index merge 优化技术,对同一个表可以使用多个索引分别进行条件扫描。
如执行计划中的语句:
UPDATE test_table SET `status` = 1 WHERE `trans_id` = '38' AND `status` = 0 ;
MySQL会根据 trans_id = ‘38’ 这个条件,利用 uniq_trans_id 索引找到叶子节点中保存的id值;同时会根据 status = 0 这个条件,利用 idx_status 索引找到叶子节点中保存的id值;然后将找到的两组id值取交集,最终通过交集后的id回表,也就是通过 PRIMARY 索引找到叶子节点中保存的行数据。
这里可能很多人会有疑问了,uniq_trans_id 已经是一个唯一索引了,通过这个索引最终只能找到最多一条数据,那MySQL优化器为啥还要用两个索引取交集,再回表进行查询呢,这样不是多了一次 idx_status 索引查找的过程么。我们来分析一下这两种情况执行过程。

上边两种情况,主要区别在于,第一种是先通过一个索引把数据找到后,再用其它查询条件进行过滤;第二种是先通过两个索引查出的id值取交集,如果取交集后还存在id值,则再去回表将数据取出来。
当优化器认为第二种情况执行成本比第一种要小时,就会出现索引合并。(生产环境流水表中 status = 0 的数据非常少,这也是优化器考虑用第二种情况的原因之一)。
为什么用了 index_merge就死锁了

上面简要画了一下两个update事务加锁的过程,从图中可以看到,在 idx_status 索引和 PRIMARY (聚簇索引) 上都存在重合交叉的部分,这样就为死锁造成了条件。
如,当遇到以下时序时,就会出现死锁:

事务1等待事务2释放锁,事务2等待事务1释放锁,这样就造成了死锁。
MySQL检测到死锁后,会自动回滚代价更低的那个事务,如上边的时序图中,事务1持有的锁比事务2少,则MySQL就将事务1进行了回滚。
解决方案
一、从代码层面
- where 查询条件中,只传 trans_id ,将数据查询出来后,在代码层面判断 status 状态是否为0;
- 使用 force index(uniq_trans_id) 强制查询语句使用 uniq_trans_id 索引;
- where 查询条件后边直接用 id 字段,通过主键去更新。
二、从MySQL层面
- 删除 idx_status 索引或者建一个包含这俩列的联合索引;
- 将MySQL优化器的index merge优化关闭。
注:MySQL官方已经确认了此bug:77209
https://bugs.mysql.com/bug.php?id=77209
相关文章:
锁--07_2---- index merge(索引合并)引起的死锁
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 案例分析生产背景死锁日志表结构执行计划 EXPLAN为什么会用 index_merge(索引合并)为什么用了 index_merge就死锁了解决方案注:M…...
后端打印不了trace等级的日志?-SpringBoot日志打印-Slf4j
在调用log变量的方法来输出日志时,有以上5个级别对应的方法,从不太重要,到非常重要 调用不同的方法,就会输出不同级别的日志。 trace:跟踪信息debug:调试信息info:一般信息warn:警告…...
声明式编程Declarative Programming
接下来要介绍第五种编程范式 -- 声明式编程。分别从它的优缺点、案例分析和适用的编程语言这三个方面来介绍这个歌编程范式。 声明式编程是一种编程范式,其核心思想是通过描述问题的性质和约束,而不是通过描述解决问题的步骤来进行编程。这与命令式编程…...
人工智能与天文:技术前沿与未来展望
人工智能与天文:技术前沿与未来展望 一、引言 随着科技的飞速发展,人工智能(AI)在各个领域的应用越来越广泛。在天文领域,AI也发挥着越来越重要的作用。本文将探讨人工智能与天文学的结合,以及这种结合带…...
JeecgBoot 框架升级至 Spring Boot3 的实战步骤
JeecgBoot 框架升级 Spring Boot 3.1.5 步骤 JEECG官方推出SpringBoot3分支:https://github.com/jeecgboot/jeecg-boot/tree/springboot3 本次更新由于属于破坏式更新,有几个生态内的组件,无法进行找到平替或无法升级,目前尚不完…...
论文阅读——Semantic-SAM
Semantic-SAM可以做什么: 整合了七个数据集: 一般的分割数据集,目标级别分割数据集:MSCOCO, Objects365, ADE20k 部分分割数据集:PASCAL Part, PACO, PartImagenet, and SA-1B The datasets are SA-1B, COCO panopt…...
gitlab下载,离线安装
目录 1.下载 2.安装 3.配置 4.启动 5.登录 参考: 1.下载 根据服务器操作系统版本,下载对应的RPM包。 gitlab官网: The DevSecOps Platform | GitLab rpm包官网下载地址: gitlab/gitlab-ce - Results in gitlab/gitlab-ce 国内镜像地…...
【SpringBoot篇】Interceptor拦截器 | 拦截器和过滤器的区别
文章目录 🌹概念⭐作用 🎄快速入门⭐入门案例代码实现 🛸拦截路径🍔拦截器interceptor和过滤器filter的区别🎆登录校验 🌹概念 拦截器(Interceptor)是一种软件设计模式,…...
conan入门(三十六):在set_version方法中从pom.xml中读取版本号实现动态版本定义
一般情况下,我们通过self.version字段定义conan 包的版本号如下: class PkgConan(ConanFile):name "pkg"version "1.7.3"因为版本号是写死的,所以这种方式有局限性: 比如我的java项目中版本号是在pom.xml中…...
为什么 GAN 不好训练
为什么 GAN 不好训练?先看 GAN 的损失: 当生成器固定时,堆D(x)求导,推理得到(加号右边先对log求导,再对负项求导) 然后在面对最优Discriminator时,Generator的优化目标就变成了&…...
select、poll、epoll 区别有哪些
文章目录 select、poll、epoll 区别有哪些?select:poll:epoll: select、poll、epoll 区别有哪些? select: 它仅仅知道了,有 I/O 事件发生了,却并不知道是哪那几个流(可…...
大模型下开源文档解析工具总结及技术思考
1 基于文档解析工具的方法 pdf解析工具 导图一览: PyPDF2提取txt: import PyPDF2 def extract_text_from_pdf(pdf_path):with open(pdf_path, rb) as file:pdf_reader PyPDF2.PdfFileReader(file)num_pages pdf_reader.numPagestext ""f…...
【华为数据之道学习笔记】5-4 数据入湖方式
数据入湖遵循华为信息架构,以逻辑数据实体为粒度入湖,逻辑数据实体在首次入湖时应该考虑信息的完整性。原则上,一个逻辑数据实体的所有属性应该一次性进湖,避免一个逻辑实体多次入湖,增加入湖工作量。 数据入湖的方式…...
Vue3-03-reactive() 响应式基本使用
reactive() 的简介 reactive() 是vue3 中进行响应式状态声明的另一种方式; 但是,它只能声明 【对象类型】的响应式变量,【不支持声明基本数据类型】。reactive() 与 ref() 一样,都是深度响应式的,即对象嵌套属性发生了…...
OpenAI开源超级对齐方法:用GPT-2,监督、微调GPT-4
12月15日,OpenAI在官网公布了最新研究论文和开源项目——如何用小模型监督大模型,实现更好的新型对齐方法。 目前,大模型的主流对齐方法是RLHF(人类反馈强化学习)。但随着大模型朝着多模态、AGI发展,神经元…...
TeeChart.NET 2023.11.17 Crack
.NET 的 TeeChart 图表控件提供了一个出色的通用组件套件,可满足无数的图表需求,也针对重要的垂直领域,例如金融、科学和统计领域。 数据可视化 数十种完全可定制的交互式图表类型、地图和仪表指示器,以及完整的功能集,…...
计算机网络常见的缩写
计算机网络常见缩写 通讯控制处理机(Communication Control Processor)CCP 前端处理机(Front End Processor)FEP 开放系统互连参考模型 OSI/RM 开放数据库连接(Open Database Connectivity)ODBC 网络操作系…...
vue cli 脚手架之配置代理
方法二...
STM32启动流程详解(超全,startup_stm32xx.s分析)
单片机上电后执行的第一段代码 1.初始化堆栈指针 SP_initial_sp 2.初始化 PC 指针Reset_Handler 3.初始化中断向量表 4.配置系统时钟 5.调用 C 库函数_main 初始化用户堆栈,然后进入 main 函数。 在正式讲解之前,我们需要了解STM32的启动模式。 STM32的…...
小程序接口OK,桌面调试接口不行
手机小程序OK,桌面版出现问题; 环境:iis反向url的tomcat服务,提供接口。 该接口post了一个很大的数组,处理时间比较久。 1)桌面调试出现错误,提示 用apipost调用接口同样出错, 502 - Web 服务器在作为网关或代理服…...
Eclipse构建后处理:从ELF到HEX的自动化转换实践
1. 为什么需要从ELF转换到HEX? 在嵌入式开发领域,特别是汽车电子控制器(ECU)开发中,我们经常会遇到两种关键的可执行文件格式:ELF和HEX。ELF(Executable and Linkable Format)是编译…...
【限时解密】Google内部测试版Gemini插件Beta通道开放倒计时——附3个已验证的早期功能入口及Token获取密钥
更多请点击: https://intelliparadigm.com 第一章:Gemini Chrome浏览器插件的演进脉络与Beta通道战略意义 Gemini Chrome 插件自 2023 年底首次公开测试以来,已历经三次重大架构重构:从初始的轻量级内容注入脚本,演进…...
[特殊字符] 论文查重居然能白嫖?这个AI工具的底层逻辑,今天给你讲透
同学们,我是你们的论文写作科普老友。 今天这期不教写作技巧,专门来聊一个所有人写完论文都绕不开、却很少有人真正搞懂的东西——查重。 你肯定遇到过这种场景:论文写了两万字,满怀信心提交查重,结果报告一出来&…...
【ElevenLabs Creator计划终极避坑手册】:基于137份真实申请案例的数据复盘——高通过率申请者的3个共性特征
更多请点击: https://intelliparadigm.com 第一章:ElevenLabs Creator计划全景认知与申请价值重定义 ElevenLabs Creator 计划并非传统意义上的 API 试用通道,而是面向内容创作者、开源贡献者与教育实践者的深度协作生态入口。其核心价值已从…...
电商选品神器:Open Claw + 淘宝 API,一键实现商品监控与智能选品
在电商运营、跨境铺货、店铺竞品分析场景中,实时获取淘宝商品数据、自动监控价格 / 销量 / 库存变化是提升选品效率的核心环节。传统手动查品耗时费力,借助 Open Claw 搭配淘宝专业 API,无需爬虫、绕过风控,就能快速搭建稳定的商品…...
Dism++终极指南:5个核心功能让Windows系统优化变得简单快速
Dism终极指南:5个核心功能让Windows系统优化变得简单快速 【免费下载链接】Dism-Multi-language Dism Multi-language Support & BUG Report 项目地址: https://gitcode.com/gh_mirrors/di/Dism-Multi-language Dism是一款基于微软DISM技术开发的强大Win…...
手把手教你用FPGA+CORDIC算法实现任意角度图像旋转(告别浮点运算)
FPGACORDIC算法实现高精度图像旋转的硬件优化实践 在数字图像处理领域,实时图像旋转是一项基础而关键的技术需求。传统基于浮点运算的旋转方案虽然直观,但在FPGA等硬件平台上往往面临资源占用高、时序难以满足的挑战。本文将深入探讨如何利用CORDIC&…...
CCM实战调校:从原理到精准色彩还原
1. 色彩校正矩阵(CCM)的核心原理 色彩校正矩阵(CCM)是图像处理流水线中一个关键的数学工具,它的主要作用是修正相机传感器捕获的颜色与实际场景颜色之间的偏差。想象一下,你用手机拍了一张草莓的照片&…...
迪士尼收购卢卡斯影业:顶级IP运营与商业并购的教科书案例
1. 一笔改变好莱坞格局的交易:迪士尼收购卢卡斯影业深度解析2012年10月30日,一则新闻震动了全球娱乐产业和无数影迷的心:华特迪士尼公司宣布,将以约40.5亿美元的价格,收购乔治卢卡斯创立的卢卡斯影业及其旗下最核心的资…...
凰标:让草根创作不再被资本随意定义@凤凰标志
——一场属于民间的反垄断革命当代文娱行业最大的不公,从来不是草根缺乏创作能力,而是资本垄断了全部的定义权与话语权。 长期以来,从作品好坏、内容价值、审美取向到行业前途,所有评判标准皆由资本制定、流量数据裁定。无数底层创…...
