MySQL的index merge(索引合并)导致数据库死锁分析与解决方案

这篇具有很好参考价值的文章主要介绍了MySQL的index merge(索引合并)导致数据库死锁分析与解决方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

在DBS-集群列表-更多-连接查询-死锁中,看到9月22日有数据库死锁日志,后排查发现是因为mysql的优化-index merge(索引合并)导致数据库死锁。

定义

index merge(索引合并):该数据库查询优化的一种技术,在mysql 5.1之后进行引入,它可以在多个索引上进行查询,并将结果合并返回。

mysql数据库的锁机制

在排查问题之前,首先讲一下mysql数据库的锁机制:

1 加锁的基本单位是 next-key lock(记录锁+间隙锁),当记录锁或者间隙锁能够解决幻读的问题,就会退化为记录锁(行锁),间隙锁。

2 加锁是将锁加在了索引之上,而不是数据之上。

3 对于当前读,索引进行加锁,当前读语句包括了(select ... from. ... for update,select...from ..... lock in share mode,update...,delete....)。

4 加锁根据唯一性索引、非唯一性索引进行了区分,根据查询条件分为了等值查询、范围查询,根据是否能够查到数据又分为了记录存在和不存在的情况。

本次死锁问题使用的索引是非唯一性索引的等值查询中记录存在的情况,因此本文仅仅详细介绍这种情况,其它情况可以查看最下面的参考文档1:

加锁情况是:会依次扫描,首先扫描到条件匹配的数据,加一个next-key lock,然后接下来扫描到第一个记录不匹配的数据,增加一个间隙锁,最后对查到记录的主键增加一个记录锁,

针对以上情况加了三种锁,加锁的目的是为了防止幻读的发生。

针对二级索引的锁进行分析:

表结构:

CREATE TABLE `jdi_roster_apply_detail` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `apply_id` varchar(100) NOT NULL COMMENT '申请单号',
  `status` tinyint(10) NOT NULL COMMENT '状态',
  PRIMARY KEY (`id`),
  KEY `idx_status` (`status`),
  KEY `idx_apply_id` (`apply_id`)
) ENGINE=InnoDB AUTO_INCREMENT=984483 DEFAULT CHARSET=utf8 COMMENT='黑白名单申请单明细'


表数据:

id apply_id status
959651 1695369220522068998 1
960738 1695369227576173690 1
961319 1695373047673903326 1
961365 1695373122447865228 1

通过 idx_apply_id建立的b+树:

因为索引是二级索引,所以叶子节点存储的数据是主键值。

执行sql:

select * from jdi_roster_apply_detail where apply_id='1695369227576173690' for update


执行数据扫描过程

1 查到符合条件的记录,增加next-key 锁,因此锁是(1695369220522068998,1695369227576173690]

2 找到第一个不符合记录的数据增加间隙锁,因此锁是 (1695369227576173690,1695373047673903326)

3 对符合条件的主键索引增加记录锁,因此对 id=960738,增加记录锁。

针对三种锁解决的幻读:

1 如果没有第一条的next-key锁, 另一个事务增加一个apply_id=1695369227576173690, id<960738 时,该事务在进行查询时,会多一条记录,因此会造成幻读。

2 如果没有第二条的 间隙锁,另一个事务增加一个apply_id=1695369227576173690, id>960738是,该事务在进行查询时,会多一条记录,因此会造成幻读。

3 如果没有第三条的记录锁,另一条事务删除一条 id=960738的记录,该事务进行查询时,会少一条数据,因此会造成幻读。

实际问题分析

数据库死锁日志

以上日志两个事务分别执行了update语句:

#事务1
update jdi_roster_apply_detail set `status` = 10 where `status` = 1 and apply_id = '1695369220522068998'
#事务2
update jdi_roster_apply_detail set `status` = 10 where `status` = 1 and apply_id = '1695369227576173690' 


这个sql是用于将某个申请单id待审批的数据改为已审批。

因为在泰山里不能执行update语句 ,因此执行了select语句查看用的索引情况:

explain select * from  jdi_roster_apply_detail  where `status` = 1 and apply_id = '1695369220522068998'


执行的结果:

通过结果可以看出两个update语句都使用了两个索引,分别是idx_status,idx_apply_id,然后将查到的结果进行合并,因此在模拟的过程中,可以将其拆成两个查询语句。

死锁模拟

事务1 事务2 锁的范围
begin begin
select * from jdi_roster_apply_detail where apply_id = '1695369220522068998' for update idx_apply_id所以锁住了(-∞,1695369220522068998],(1695369220522068998,1695369227576173690) 主键id索引锁住了 id=959651
select * from jdi_roster_apply_detail where apply_id = '1695369227576173690' for update idx_apply_id所以锁住了(1695369220522068998,1695369227576173690],(1695369227576173690,1695373047673903326) 主键id索引锁住了 id=960738
select * from jdi_roster_apply_detail where status = 1 for update 会对idx_status上加next-key锁和间隙锁,但是在对主键959651,960738,961319,961365进行加记录锁时,其中事务2 对960738已经加了记录锁,所以该事务1进行了阻塞。
select * from jdi_roster_apply_detail where status = 1 for update 会对idx_status上加next-key锁和间隙锁,但是在对主键959651,960738,961319,961365进行加记录锁时,其中事务1对959651已经加了记录锁,所以该事务2进行了阻塞。
deadlock

两个事务分别想要两个主键id的记录锁,造成相互等待,形成了死锁。

以上是先执行idx_apply_id的索引查询再执行idx_status索引查询,如果先执行idx_status索引查询,再执行idx_apply_id的索引查询,也会因为主键的记录锁造成死锁。

解决方案

1 利用force index(idx_apply_id)强制走某个索引,这样InnoDB就会忽略index merge,避免多个索引同时加锁的情况。

2 禁用Index Merge,用命令禁用Index Merge:SET GLOBAL optimizer_switch='index_merge=off,index_merge_union=off,index_merge_sort_union=off,index_merge_intersection=off';

3 Index Merge同时使用了2个独立索引,因此新建一个包含这两个索引所有字段的联合索引,这样InnoDB就只会走这个单独的联合索引。

第三种方案相较于第一种查询性能更好,相对于第二种仅仅作用于该表,影响范围小,因此本次也是采用了该方案。

总结

该死锁问题是因为优化器使用了合并索引问题导致的,最终通过新建一个联合索引来解决这个问题。

参考文档:

1 https://www.xiaolincoding.com/mysql/lock/how_to_lock.html

作者:京东工业 李小辉

来源:京东云开发者社区 转载请注明来源文章来源地址https://www.toymoban.com/news/detail-710666.html

到了这里,关于MySQL的index merge(索引合并)导致数据库死锁分析与解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MySQL数据库唯一索引

    创建索引是指在某个表的一列或多列上建立一个索引,以便提高对表的访问速度。创建索引有3种方式,分别是1.创建表的时候创建索引、2.在已经存在的表上创建索引和使用3.ALTER TABLE语句来创建索引。 本文福利, 莬 费领取Qt开发学习资料包、技术视频,内容包括(C++语言基

    2024年02月08日
    浏览(67)
  • MySQL数据库索引的数据结构

    数据库索引的功能就是让查找更加的高效,所以索引的数据结构应该是能够加速查找的数据结构。 MySQL的innoDB存储引擎的索引的数据结构就是多叉搜索树中的b+树,这可以说是为索引量身定做的一个数据结构。 首先,索引可以通过主键,unique修饰创建,也可以直接使用sql语句

    2024年02月10日
    浏览(58)
  • 简单认识MySQL数据库索引

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 ●索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址(类似于C语言的链表通过指针指向数据记录的内存地址)。 ●使用索引后可以不用扫描全表来定位某行的

    2024年02月16日
    浏览(69)
  • 【MySQL数据库 | 第十七篇】索引以及索引结构介绍

    目录 前言: 索引简介:  索引结构:           二叉树索引结构         Tree(普通二叉树)         B-Tree(多路平衡查找树)         B+Tree          哈希索引数据结构 总结: 在实际生活中,我们对SQL语句进行优化实际上有很大一部分都是对索引进行优化,因此对索引

    2024年02月09日
    浏览(76)
  • 【MySql系列】深入解析数据库索引

    MySQL索引是数据库中一个关键的概念,它可以极大地提高查询性能,加快数据检索速度。但是,要充分发挥索引的作用,需要深入理解它们的工作原理和使用方式。 在本文中,我们将深入解析MySQL索引,探讨它们的重要性、类型、创建、维护以及最佳实践。 在数据库中,索引

    2024年02月08日
    浏览(76)
  • 【Mysql系列】——详细剖析数据库“索引”【上篇】

        😎博客昵称:博客小梦 😊最喜欢的座右铭:全神贯注的上吧!!! 😊作者简介:一名热爱C/C++,算法,数据库等技术、喜爱运动、热爱K歌、敢于追梦的小博主! 😘博主小留言:哈喽! 😄各位CSDN的uu们,我是你的博客好友小梦,希望我的文章可以给您带来一定的帮

    2024年02月02日
    浏览(56)
  • MySQL数据库索引的种类、创建、删除

    目录 一:MySQL 索引 1、MySQL 索引介绍 2、 索引的作用  3、索引的副作用 4、 创建索引的原则依据  二、索引的分类和创建 1、 普通索引 (1) 直接创建索引 (2) 修改表方式创建 (3) 创建表的时候指定索引 2、 唯一索引 (1) 直接创建唯一索引 (2) 修改表方式创建

    2024年02月09日
    浏览(212)
  • MySQL数据库的ID列添加索引

    要为MySQL数据库的ID列添加索引,可以使用以下语法: 其中, table_name 是要添加索引的表名, index_name 是索引的名称, id 是要添加索引的列名。 例如,如果要为名为 users 的表的 id 列添加索引,可以执行以下语句: 这将在 users 表的 id 列上创建名为 idx_id 的索引。 需要注意的

    2024年02月07日
    浏览(52)
  • B+树:MySQL数据库索引的实现

    作为一个软件开发工程师,你对数据库肯定再熟悉不过了。作为主流的数据存储系统,它在我们的业务开发中,有着举足轻重的地位。在工作中,为了加速数据库中数据的查找速度,我们常用的处理思路是,对表中数据创建索引。那你是否思考过,数据库索引是如何实现的呢

    2024年02月09日
    浏览(62)
  • 【MySQL索引与优化篇】数据库的设计规范

    在关系型数据库中,关于数据表设计的基本原则、规则就称为范式 。范式的英文名称是 Normal Form ,简称 NF 。它是英国人 E.F.Codd 在上个世纪70年代提出关系数据库模型后总结出来的。范式是关系数据库理论的基础,也是我们在设计数据库结构过程中所要遵循的 规则 和 指导方

    2024年02月05日
    浏览(76)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包