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 阅读 55 次 更新于 2025-10-29 04:15:31 我来答关注问题0
檬味博客在线解答立即免费咨询

mySQL相关话题

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