我是靠谱客的博主 仁爱月饼,最近开发中收集的这篇文章主要介绍insert时调用本身字段_MySQL RC级别下并发insert锁超时问题 - 案例验证,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本系列打算用三篇文章来聊聊这个事情。这是第三篇,用实际案例来证明假设。

第二篇链接:

温正湖:MySQL RC级别下并发insert锁超时问题 - 源码分析​zhuanlan.zhihu.com

我们举update为例,因为update可以转化为delete+insert,所以也就包含了insert的场景。仍然采用前述的表dt和其中的9条记录。

二级唯一索引场景

我们尝试对id为6的记录做2次update,并在第二次的时候gdb跟踪detail7_1的唯一性约束检查流程。

session1-ddb>begin;
Query OK, 0 rows affected (0.00 sec)

session1-ddb>update dt set id = 66 where id = 6;
Query OK, 1 row affected (6 min 3.98 sec)
Rows matched: 1  Changed: 1  Warnings: 0

session1-ddb>update dt set id = 666 where id = 66;

第一个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删除掉;

8d3ad1e2e057d719da8ea4f3ea8ae371.png

上图确认操作的索引的detail7_1。

ab47c2c71d4b463f458c852ea8c4c3c6.png

进一步确认删除的记录heap_no是11。

2、接下来会插入一条新的记录,在插入前会进行唯一性约束检查;

82bc1ecc0892e690de8fa50adff77d27.png

上图的调用栈最下面的红框表明此update操作进入了insert逻辑。中间红框表明进行的是唯一性约束检查。最上面的框表示当前处理的索引是detail7_1,heap_no为7表示找到的记录是id=6那条最早的记录对应的detail7_1索引记录。执行c让其继续执行:

8e96427b8f598e2bd4ab58e0674ec476.png

上图可以发现还是在row_ins_scan_sec_index_for_duplicate中,heap_no为11表示处理的是id=66的那条刚删除的记录对应的detail7_1索引记录。

也就是说我们构造出了二级唯一索引存在2个delete-marked但n_uniq相同(都为('1','6'))的记录。让gdb继续执行:

f5df9759616e7548b83d26ec76d3a7e9.png

还是在row_ins_scan_sec_index_for_duplicate中,此时处理的是heap_no为8的记录,对应的索引变为('1','7'),唯一性约束检查可以结束了。让gdb继续:

892b4badf4774ff570d773e067b6a548.png

可以发现,此时已经进入到最后一个普通二级索引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;

e9739bd1b206adb1c8139db294dc548c.png

在对主键索引调用row_upd_changes_ord_field_binary_func函数判断后,并没有进入delete-marked流程,而是马上操作二级索引了,可以发现detail7_1索引的记录需要更新。

2、更新普通列:

b9aeeac14356666a8d4787baa934264c.png

主键索引不需要delete-marked,唯一索引detail7_1也不需要。普通索引detail7_2需要。

上面就是简单的GDB调试证明过程。对于二级唯一索引的证明是充分的,因为只需要有这种场景就行。但对主键索引的证明是不充分的,因为我们并没有举例排除所有可能的场景。


前面3篇文章分析了RC隔离级别下并发insert锁超时问题。细心的同学是否发现在二级唯一索引进行唯一性冲突检查时,加的是next-key共享锁。那么为什么要加共享锁呢,RC下不应该是no gap锁吗?这个问题比较有意思,我们在第四篇来分析。

最后

以上就是仁爱月饼为你收集整理的insert时调用本身字段_MySQL RC级别下并发insert锁超时问题 - 案例验证的全部内容,希望文章能够帮你解决insert时调用本身字段_MySQL RC级别下并发insert锁超时问题 - 案例验证所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部