请选择 进入手机版 | 继续访问电脑版
DDB(网易杭研自研的MySQL数据库中间件产品)团队小伙伴发现了一个问题,觉得比较奇怪。于是找到我们,希望解释下。过程中除解释了问题的现象,也通过代码了解了更多的InnoDB DML执行逻辑,还发现了MySQL/InnoDB官方在二级唯一索引冲突检查时加锁行为的反复。本系列打算用三四篇文章来聊聊这个事情。这是第三篇,用实际案例来证明假设。
第二篇链接:
温正湖:MySQL RC级别下并发insert锁超时问题 - 源码分析​zhuanlan.wengbi.com我们举update为例,因为update可以转化为delete+insert,所以也就包含了insert的场景。依旧采用前述的表dt和其中的9条记录。
二级唯一索引场景

我们尝试对id为6的记录做2次update,并在第二次的时候gdb跟踪detail7_1的唯一性约束检查流程。
[code][/code]第一个update将主键id为6的记录更新为66,按照代码逻辑,由于修改了n_uniq字段,所以会走delete+insert,而detail7_1由于主键id在其n_fields中,所以也需要更新该索引,也是走delete+insert。此时detail7_1就存在2条n_uniq均为('1','6')的记录,第一条应该是heap_no为7,第二条应该heap_no为11。
第二个update将主键id为66及记录更新为666,执行的代码逻辑跟第一次update类似,但在唯一性约束检查时需要分别判断heap_no为7和11的记录,并进一步获取heap_no为8的记录('1','7')。代码执行过程如下:
1、首先会将已经存在的当前记录调用btr_cur_del_mark_set_sec_rec删除掉;
MySQL RC级别下并发insert锁超时问题 - 案例验证-2.jpg
上图确认操作的索引的detail7_1。
MySQL RC级别下并发insert锁超时问题 - 案例验证-3.jpg
进一步确认删除的记录heap_no是11。
2、接下来会插入一条新的记录,在插入前会进行唯一性约束检查;
MySQL RC级别下并发insert锁超时问题 - 案例验证-4.jpg
上图的调用栈最下面的红框表明此update操作进入了insert逻辑。中间红框表明进行的是唯一性约束检查。最上面的框表示当前处理的索引是detail7_1,heap_no为7表示找到的记录是id=6那条最早的记录对应的detail7_1索引记录。执行c让其继续执行:
MySQL RC级别下并发insert锁超时问题 - 案例验证-5.jpg
上图可以发现还是在row_ins_scan_sec_index_for_duplicate中,heap_no为11表示处理的是id=66的那条刚删除的记录对应的detail7_1索引记录。
也就是说我们构造出了二级唯一索引存在2个delete-marked但n_uniq相同(都为('1','6'))的记录。让gdb继续执行:
MySQL RC级别下并发insert锁超时问题 - 案例验证-6.jpg
还是在row_ins_scan_sec_index_for_duplicate中,此时处理的是heap_no为8的记录,对应的索引变为('1','7'),唯一性约束检查可以结束了。让gdb继续:
MySQL RC级别下并发insert锁超时问题 - 案例验证-7.jpg
可以发现,此时已经进入到最后一个普通二级索引detail7_2的处理流程。
从上面构造的场景至少可以说明二级唯一索引存在索引键值相同的多条记录。所以在唯一性约束检查时需要使用while循环不断获取游标中的下一条记录,直到发现索引键值不同的记录,如果该记录被其他事务锁住,那么就会导致当前事务阻塞并引发锁超时。
主键索引场景

该场景我们只需要构造不更新主键id,而是更新二级索引列或普通列,观察是否会进入btr_cur_del_mark_set_clust_rec。所以我们尝试对主键id为4的记录做如下更新:
1、更新二级索引列:
session1-ddb>update dt set coupon_id='2' where id = 4;
MySQL RC级别下并发insert锁超时问题 - 案例验证-8.jpg
在对主键索引调用row_upd_changes_ord_field_binary_func函数判断后,并没有进入delete-marked流程,而是马上操作二级索引了,可以发现detail7_1索引的记录需要更新。
2、更新普通列:
MySQL RC级别下并发insert锁超时问题 - 案例验证-9.jpg
主键索引不需要delete-marked,唯一索引detail7_1也不需要。普通索引detail7_2需要。

上面就是简单的GDB调试证明过程。对于二级唯一索引的证明是充分的,因为只需要有这种场景就行。但对主键索引的证明是不充分的,因为我们并没有举例排除所有可能的场景。
前面3篇文章分析了RC隔离级别下并发insert锁超时问题。细心的同学是否发现在二级唯一索引进行唯一性冲突检查时,加的是next-key共享锁。那么为什么要加共享锁呢,RC下不应该是no gap锁吗?这个问题比较有意思,我们在第四篇来分析。
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|翁笔

© 2001-2018 Wengbi.com

返回顶部