MySQL多个二级索引并发更新触发死锁

所以第一个事务先根据group_id索引,已经锁住primary id,然后再根据test_id索引,锁定primary id; 第二个事务先根据test_id索引,已经锁住primary id,然后再根据group_id索引,去锁primary id; 所以这样并发更新就可能出现死索引。 MySQL官方也已经确认了此bug: bugs.mysql.com/bug.php?...再看出...
MySQL多个二级索引并发更新触发死锁
删除实例失败,报错db死锁。

事务一:

持有 i-ybsxzr5spk1234567890 锁,去获取 bi-ybrurprssf1234567890 锁;

事务二:

持有 bi-ybrurprssf1234567890 锁,去获取 i-ybsxzr5spk1234567890 锁;

事务一获取 i-ybsxzr5spk1234567890 的锁很好理解,但是这两个事务还要获取 bi-ybrurprssf1234567890 这个锁,看似和这两个update没有关系。

原因是上述两个update语句在执行时,用到了mysql的索引合并。

什么是索引合并( blog.csdn.net/w10140747..., dev.mysql.com/doc/refma...):

索引合并引发死锁( modb.pro/db/58619):

所以第一个事务先根据group_id索引,已经锁住primary id,然后再根据test_id索引,锁定primary id; 第二个事务先根据test_id索引,已经锁住primary id,然后再根据group_id索引,去锁primary id; 所以这样并发更新就可能出现死索引。 MySQL官方也已经确认了此bug: bugs.mysql.com/bug.php?...

再看出问题的两个update语句,where中有两个条件:instance_id 和 deleted_at,并且表结构中有对应两列单独的索引。

解释为什么两个update还要锁 bi-ybrurprssf1234567890,就是因为索引合并中根据 deleted_at 筛选到了 bi-ybrurprssf1234567890 这条记录,并尝试去给这个主键加锁。

表结构复现数据集

gitee.com/chen_zhuohan/...

代码如何避免

总的来说,当你的sql有这种情况,那mysql很有可能用索引合并,就会存在死锁风险:

sql用到了索引合并并非是一个最优的方案,反而证明你的sql需要为索引合并的列建立组合索引。一方面避免上述死锁问题,另一方面索引合并也会有性能损耗,不如直接用组合索引。

2. 使用主键更新列;

更新时where中有主键时,innodb会自动选用PRIMARY索引,而非索引合并。

3. (不推荐)where中的单列索引条件筛选出的结果数很少,比如唯一索引;

4. (不推荐)关闭优化器的index merge优化。

参考文档

MySQL 案例:Update 死锁详解

一次 MySQL 线上死锁分析实战

Reference:2024-09-04
mengvlog 阅读 30 次 更新于 2025-08-09 16:38:37 我来答关注问题0
  • mysql的读写之间是可以并发的,普通的select是不需要锁的,当查询的记录遇到锁时,用的是一致性的非锁定快照读,也就是根据数据库隔离级别策略,会去读被锁定行的快照,其它更新或加锁读语句用的是当前读,读取原始行;因为普通读与写不冲突,所以innodb不会出现读写饿死的情况,又因为在使用索引的时候...

  •  翡希信息咨询 MySQL索引的理解(主键索引和二级索引)

    二级索引: 建立基础:二级索引是在一级索引的基础上建立的,辅助查找数据。 存储内容:叶子节点存储的是主键值,通过这个主键值可以快速定位到一级索引,再进行数据查找。 应用场景:在处理非主键列的查询时大显身手,但插入和更新操作可能需要两步查找,效率相对较低。索引的结构与查询策略: B+树结构...

  •  武汉誉祥科技 MySQL索引的理解(主键索引和二级索引)

    二级索引则是在一级索引的基础上建立的,它以一级索引(主键)作为索引,辅助查找数据。叶子节点存储的是主键值,通过这个线索,数据库可以快速定位到一级索引,再进行数据查找。二级索引在处理非主键列的查询时大显身手,但插入和更新操作可能需要两步查找,效率相对较低。B+树的力量 索引结构的选择往往...

  • 如果没有定义主键,MySQL会自动选择第一个唯一索引(unique)且只包含非空列(NOT NULL)作为主键,InnoDB会使用这个唯一索引作为聚簇索引。如果没有这样的列,InnoDB会自动生成一个这样的ID值,它有六个字节,并且是隐藏的,作为聚簇索引的一部分。聚簇索引决定了数据在磁盘上的存储顺序,而二级索引则存...

  •  文暄生活科普 MySQL二级索引

    创建二级索引的操作,MySQL中映射为ALTER TABLE ADD_INDEX。创建二级索引格式示例:新建age字段二级索引,MySQL分别创建id主键聚簇索引和age二级索引,聚簇索引叶子节点存整行数据,二级索引叶子节点存主键值。二级索引创建流程包含三个阶段:DDL prepare、DDL执行与DDL commit。DDL prepare阶段,DDL执行阶段中...

檬味博客在线解答立即免费咨询

mySQL相关话题

Copyright © 2023 WWW.MENGVLOG.COM - 檬味博客
返回顶部