文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

【MySQL】说透锁机制(二)行锁 加锁规则 之 范围查询(你知道会锁表吗?)

2023-08-16 22:13

关注

本文会按照 聚集集索->唯一索引->普通索引 的顺序 地毯式分析 范围查询中 <<=>>= 的行锁情况,锁表分析在唯一索引 章节,万字长文,力求分析全面,很硬核全网独一份,记得收藏 当然如果落下什么欢迎大家评论指出!

在上文,我们介绍了 MySQL InnoDB行锁的:

并对等值查询3类索引 时,结合案例 说明了 都加了哪些锁 以及 为什么加这些锁的分析:

详细案例分析和总结,请见上文:行锁 加锁规则 之 等值查询



本文我们主要分析 范围查询,主要包括: <<=>>= 等.

文章很长,我先给出结论
聚集索引
对于 聚集索引下的范围查询 <、<=、>、>=,无论是否组合,都会遵循如下规则

详细说透结论

  • 从上锁的对象来说:
    • 对所有匹配的聚集索引记录上锁是应该的;
    • 由于是范围,和等值匹配不同,当索引从左向右扫描到匹配记录时,不能立即停止,因为可能还有其它匹配记录,所以 直到扫描到 [不匹配的索引记录] 才能停止,然后上锁也是合理的。(至于<=的等值(=)的问题,文章中会有详细说明,这里实际是有争议的);
    • 对于 >和>=,因为会包括 索引最大值 后面的间隙,所以 对上界面伪值supremum 上锁也是应该的。
  • 从上锁的类型来说:
    • 咱们上文曾说过,行锁默认的是Next-key Lock,可能会降级为Gap Lock或Record Lock。因为这里是范围查询,匹配的值会有多个,所以不降级也无不妥;
    • 这里仅对 聚集索引的 >= 的等值(=)做了降级优化,因为对每个索引值上Next-key Lock或Gap Lock时,负责的是 前面的间隙,所以<=的等值(=)不可以做降级,降级就可能出现幻读问题了。

唯一索引 和 普通索引:
对于 唯一索引 和 普通索引 下的范围查询 <、<=、>、>=,无论是否组合,都会遵循如下规则

  • 从上锁的对象来说:
    • 对所有匹配的索引记录上锁是应该的;
    • 对所有匹配的索引记录 对应的 聚集索引记录 上锁,这里在等值匹配时也是如此;
    • 由于是范围,和等值匹配不同,当索引从左向右扫描到匹配记录时,不能立即停止,因为可能还有其它匹配记录,所以 直到扫描到 [不匹配的索引记录] 才能停止,然后上锁也是合理的;
    • 对于 >和>=,因为会包括 索引最大值 后面的间隙,所以 对上界面伪值supremum 上锁也是应该的。
  • 从上锁的类型来说:
    • 这里仅对 对应的聚集索引记录上Record Lock也是合理的,要不然锁的范围太大了;
    • 这里 并没有像 聚集索引的 >= 的等值(=)做降级优化,其实唯一索引理论上是可以的。

OK,给完结论,接着就让我们来验证吧 ,先看一看我们表中的数据:

+----+----------+-----+--------+--------+| id | name     | abc | abc_uk | remark |+----+--------- +-----+--------+--------+| 10 | 巴西     |  10 |     10 | NULL   || 15 | 克罗地亚 |  10 |     15 | NULL   || 20 | 阿根廷   |  20 |     20 | NULL   || 30 | 葡萄牙   |  30 |     30 | NULL   || 40 | 法国     |  40 |     40 | NULL   |+----+----------+-----+--------+--------+5 rows in set (0.02 sec)

id :自增主键
abc :普通索引
abc_uk :唯一索引

新打开一个mysql客户端,我们叫Session1,并开启锁监视器:

SET GLOBAL innodb_status_output=ON;SET GLOBAL innodb_status_output_locks=ON;

说明,本文基于:MySQL5.7、InnoDB引擎、可重复读事务隔离级别


小于

新打开一个mysql客户端,我们叫Session2, 执行SQL如下(按id < 20):

begin;update ct set remark = '巴西 爆冷 克罗地亚' where id < 20;

注意不要commit或rollback,以便于我们分析行锁

这里匹配id < 20 的 记录有两条:
![在这里插入图片描述](https://img-blog.csdnimg.cn/bacea057d038408bbce106054cd8c5a2.png
然后我们在Session1里查看锁的详细信息

show engine innodb status\G; 

我们还是主要看TRANSACTIONS这段,如下图:
在这里插入图片描述

这里上了 3 把锁,因为是 按id,所以全锁在 聚集索引 上:

  1. id = 20 (向右扫描到的第一个不匹配记录): Next-key Lock;
  2. id = 10(匹配记录) : Next-key Lock;
  3. id = 15(匹配记录) : Next-key Lock;

因为 20 刚好是临界值。如果我们换成 id < 19呢?

update ct set remark = '巴西 爆冷 克罗地亚' where id < 19;

再来看一下:

show engine innodb status\G; 

在这里插入图片描述
结果依旧!!!(你可以对比一下:上一个事务ID是:793365):
还有一个临界值 id < 16

update ct set remark = '巴西 爆冷 克罗地亚' where id < 16;

结果也是一样的,就不展示了。

所以对于 < 在 聚集索引 上来说,我们得出的结果是:

小于等于

这里依旧演示两个临界值: id <=19 和 id <= 20

begin;update ct set remark = '巴西 爆冷 克罗地亚' where id <= 19;

这里匹配记录有 id =10 和 id =15 两条记录。

我们来看一下:

show engine innodb status\G; 

在这里插入图片描述
不出所料,因为 和 id < 19 的匹配记录是相同的,所以锁的结果也是相同的!
我们再来看一下临界值 id <=20:

begin;update ct set remark = '巴西 爆冷 克罗地亚' where id <= 20;

我们看一下修改的记录,共3条:
在这里插入图片描述
这里对于 3条匹配的 索引记录,上Next-key Lock已尽在我们掌握中,但id = 30 是否会上锁?
如果上的话,是上 Next-key Lock 还是Gap Lock?

我们来看一下:

show engine innodb status\G; 

在这里插入图片描述
可以看出上了4把锁:3条已匹配记录上了Next-key Lock,向右查找到不匹配的30也上了Next-key Lock。
其实这里不知道你会不会有这个 疑问 :对于聚集索引来说,值是唯一的,既然已经匹配到最大的20了,中止是不是更好?为什么还要继续向右?
如果是<=21,因为21不存在,所以需要继续向右扫描直到查找到30,上一把Next-key Lock倒可以理解!

其实疑问早就存在,前腾讯云数据库负责人林晓斌还曾找社区专家讨论过,官方bug系统上也有提到,但是并未被verified,所以这个也被他称之为bug!

对于 <= 在 聚集索引 上来说,我们得出的结果是(实际和 < 一样):

大于

我们再来验证 id > 10:

update ct set remark = '巴西 爆冷 克罗地亚' where id > 10;

这时匹配的记录有 15、20、30、40,所以会上4把Next-key Lock,对于40后的间隙,是对supremum上了Next-key Lock,这个很好理解,没什么特殊的,请看下图:
在这里插入图片描述
对于 > 在 聚集索引 上来说,我们得出的结果是(实际和 <, <= 类似):

大于等于

我们最后来看一下 id >= 10,这个有点特殊

update ct set remark = '巴西 爆冷 克罗地亚' where id >= 10;

在这里插入图片描述

对于 >= 我们得到的结果是:

范围组合

范围组合一: > <

update ct set remark = '匹配15' where id > 10 and id < 20;

在这里插入图片描述
由图可知,对2条索引记录上锁:匹配:15,next-key:20
结果

范围组合二: > <=

update ct set remark = '匹配15 + 20' where id > 10 and id <= 20;

在这里插入图片描述
由图可知,对3条索引记录上锁:匹配:15、20,next-key:30

结果 和> <相同,不做赘述!

范围组合三: >= <

update ct set remark = '匹配10 + 15' where id >= 10 and id < 20;

在这里插入图片描述
由图可知,对3条索引记录上锁:匹配:10、15,next-key:20
结果

范围组合四: >= <=

update ct set remark = '匹配10 + 15 + 20' where id >= 10 and id <= 20;

在这里插入图片描述
由图可知,对4条索引记录上锁:匹配:10、15、20,next-key:30
结果 和>= <相同,不做赘述!

聚集索引 小结

对于 聚集索引下的范围查询 <、<=、>、>=,无论是否组合,都会遵循如下规则:


小于

我们在Session2 执行SQL如下(按abc_uk < 20):

update ct set remark = '巴西 爆冷 克罗地亚' where abc_uk < 20;

在这里插入图片描述
这里共匹配2条记录:abc_uk = 10 和 abc_uk = 15。

共上了 6 把锁,3把锁在唯一索引上:

  1. abc_uk = 20 (向右扫描到的第一个不匹配记录): Next-key Lock;
  2. abc_uk = 10(匹配记录) : Next-key Lock;
  3. abc_uk = 15(匹配记录) : Next-key Lock;

3把锁在聚集索引上:

  1. id = 20 (向右扫描到的第一个不匹配记录): Record Lock;
  2. id = 10(匹配记录) : Record Lock;
  3. id = 15(匹配记录) : Record Lock;

到这,我猜你肯定认为 和 聚集索引 一样有结果了,请看好了,好戏即将上演~
我改下sql,sql语句本身没变,只是 20换成30:

update ct set remark = '巴西 爆冷 克罗地亚' where abc_uk < 30;

这里共匹配3条记录,分别是abc_uk = 10 、15、20。
我们看一下锁监视器:
在这里插入图片描述
这里对聚集索引上了6把锁!!!
表里所有的5条聚集索引记录都上了Next-key Lock,还把supremum上了Next-key Lock。

你是不是会怀疑我搞错了?

那咱们走着瞧~,咱们先看一下explain的结果:
在这里插入图片描述
possible_keys: uk_abc_uk,意思说可能走的索引是uk_abc_uk
key:PRIMARY,意思说实际走的索引是聚集索引
type:index,意思说扫描了整个索引树

所以:这条SQL并没有使用唯一索引,而使用的是全表扫描
这里其实是索引相关的知识,也就是索引失效了,实际是通过索引成本计算,得出全表扫描的cost(3.9) 小于唯一索引再回表的cost(4.61):
在这里插入图片描述
全表扫描的成本计算(上图):

在这里插入图片描述
使用唯一索引的成本计算(上图):

说白了,就是表里一共才5条记录,这个范围就匹配了3条记录,我用唯一索引先查id,再用id回表去修改,还不如直接遍历全表来的快!!!
实际项目里,表里的数据一般不会这么少,所以这个示例的修改占比(60%)还是很高的,所以才造成了全表扫描(全表成本低于使用索引)。

对于索引要细说的话内容很多,远没有这么简单,这里只是简单说明,不懂不要紧,先作为了解,后面再安排细聊索引的成本计算

安排结果!对于 < 在 唯一索引 上来说,我们得出的结果是:

小于等于

update ct set remark = '巴西 爆冷 克罗地亚' where abc_uk <= 19;

在这里插入图片描述
不出所料,因为 和 abc_uk < 20 的匹配记录是相同的,所以锁的结果也是相同的!

我们再来看一下临界值 abc_uk <=20:

begin;update ct set remark = '巴西 爆冷 克罗地亚' where abc_uk <= 20;

这里依然是会影响到3条记录 abc_uk = 10、15、20,所以你懂的,又锁表了!!! 具体就不截图了。

所以我们改成范围小一点的临界值 abc_uk <=15:

begin;update ct set remark = '巴西 爆冷 克罗地亚' where abc_uk <= 15;

这里只会影响到2条记录 abc_uk = 10、15

我们来看一下:

show engine innodb status\G; 

在这里插入图片描述
这里共匹配2条记录:abc_uk = 10 和 abc_uk = 15。

共上了 6 把锁,3把锁在唯一索引上:

  1. abc_uk = 20 (向右扫描到的第一个不匹配记录): Next-key Lock;
  2. abc_uk = 10(匹配记录) : Next-key Lock;
  3. abc_uk = 15(匹配记录) : Next-key Lock;

3把锁在聚集索引上:

  1. id = 20 (向右扫描到的第一个不匹配记录): Record Lock;
  2. id = 10(匹配记录) : Record Lock;
  3. id = 15(匹配记录) : Record Lock;

综上,对于 <= 在 聚集索引 上来说,我们得出的结果 实际和 < 一样,不做赘述!

大于

我们先来验证 abc_uk > 10:

update ct set remark = '阿根廷 3:0 克罗地亚' where abc_uk > 10;

这里共匹配4条记录:abc_uk = 15、20、30、40,所以你懂的,又锁表了!!! 具体就不截图了。

所以我们改成范围小一点的 abc_uk > 20:

update ct set remark = '阿根廷 3:0 克罗地亚' where abc_uk > 20;

这里只会影响到2条记录 abc_uk = 30、40

我们来看一下:

show engine innodb status\G; 

在这里插入图片描述
这里共匹配2条记录:abc_uk = 30 和 abc_uk = 40。

共上了 5把锁,3把锁在唯一索引上:

  1. abc_uk = supremum (上界限伪值,锁的是最大值后的间隙): Next-key Lock;
  2. abc_uk = 30(匹配记录) : Next-key Lock;
  3. abc_uk = 40(匹配记录) : Next-key Lock;

2把锁在聚集索引上:

  1. id = 30(匹配记录) : Record Lock;
  2. id = 40(匹配记录) : Record Lock;

对于 > 在 唯一索引 上来说,我们得出的结果是(实际和 <, <= 类似):

大于等于

因为 abc_uk >= 10匹配了所有记录,所以你懂的,又锁表了!!! 具体就不截图了。

我们直接来看不锁表的 abc_uk >= 30

update ct set remark = '阿根廷 3:0 克罗地亚' where abc_uk >= 30;

在这里插入图片描述
从上图可知,abc_uk >= 30 和 abc_uk > 20 上的锁是一样的,并不像 id >= 时那样将匹配值优化为Record Lock。

所以,对于 >= 我们得到的结果 实际和 > 一样,不做赘述!

范围组合

说明:索引失效 会 锁表 的规则是通用的,所以这里就 统一 只演示 不锁表 的情况。

范围组合一: > <

update ct set remark = '格子军团' where abc_uk > 10 and abc_uk < 20;

在这里插入图片描述
不出所料,由图可知,对 2条唯一索引 和对应的 2条聚集索引 上锁:匹配:15,next-key:20

结果:(和单个规则相同)

范围组合二: > <=

update ct set remark = '格子军团' where abc_uk > 10 and abc_uk <= 20;

》TODO
不出所料,由图可知,对 3条唯一索引 和对应的 3条聚集索引 上锁:匹配:15、20,next-key:30

结果:(和单个规则相同)

范围组合三: >= <

update ct set remark = '梅西加油' where abc_uk >= 10 and abc_uk < 20;

在这里插入图片描述

不出所料,由图可知,对 3条唯一索引 和对应的 3条聚集索引 上锁:匹配:10、15,next-key:20
结果:(和单个规则相同)

范围组合四: >= <=

update ct set remark = '梅西加油' where abc_uk >= 10 and abc_uk <= 15;

在这里插入图片描述
不出所料,由图可知,对 3条唯一索引 和对应的 3条聚集索引 上锁:匹配:10、15,next-key:20
结果:(和单个规则相同)

唯一索引 小结

对于 唯一索引下的范围查询 <、<=、>、>=,无论是否组合,都会遵循如下规则:


说明:索引失效 会 锁表 的规则是通用的,所以这里就 统一 只演示 不锁表 的情况。

小于

我们在Session2 执行SQL如下(按abc < 20):

update ct set remark = '梅西加油' where abc < 20;

在这里插入图片描述

这里共匹配2条abc=10的记录。

所以共上了 6 把锁,3把锁在普通索引上:

  1. abc = 20 (向右扫描到的第一个不匹配记录): Next-key Lock;
  2. abc = 10,id = 10(匹配记录) : Next-key Lock;
  3. abc = 10,id = 15(匹配记录) : Next-key Lock;

3把锁在聚集索引上:

  1. id = 20 (向右扫描到的第一个不匹配记录): Record Lock;
  2. id = 10(匹配记录) : Record Lock;
  3. id = 15(匹配记录) : Record Lock;

可以看出:和唯一索引上锁规则没什么两样!

锁表只需要把范围扩大就可以复现,比如:

update ct set remark = '梅西加油' where abc < 30;

所以,对于 < 在 普通索引 上来说,我们得出的结果是(和唯一索引的 < 相同):

小于等于

update ct set remark = '梅西加油' where abc <= 19;

在这里插入图片描述
不出所料,因为 和 abc < 20 的匹配记录是相同的,所以锁的结果也是相同的!

所以,对于 <= 在 普通索引 上来说,我们得出的结果:实际和 < 一样,不做赘述.

大于

update ct set remark = '梅西加油' where abc > 20;

在这里插入图片描述

这里共匹配2条记录:abc = 30、40

共上了 5把锁,3把锁在普通索引上:

  1. abc = supremum (上界限伪值,锁的是最大值后的间隙): Next-key Lock;
  2. abc = 30(匹配记录) : Next-key Lock;
  3. abc = 40(匹配记录) : Next-key Lock;

2把锁在聚集索引上:

  1. id = 30(匹配记录) : Record Lock;
  2. id = 40(匹配记录) : Record Lock;

对于 > 在 普通索引 上来说,我们得出的结果是(实际和唯一索引的相同):

大于等于

update ct set remark = '梅西加油' where abc >= 30;

在这里插入图片描述

从上图可知,abc >= 30 和 abc > 20 的上锁是一样的,和唯一索引规则相同,并不像id>=时那样将匹配值优化为Record Lock。

所以,对于 >= 在 普通索引 上来说,我们得出的结果:实际和 > 一样,不做赘述.

范围组合

范围组合一: > <

update ct set remark = '格子军团' where abc > 10 and abc < 20;

在这里插入图片描述
不出所料,由图可知,无匹配记录,所以只对next-key:abc=20以及对应的id = 20上了锁

结果:(和单个规则相同)

因为其它范围组合实际都和单个规则相同,所以不做赘述!

普通索引 小结

对于 普通索引下的范围查询 <、<=、>、>=,无论是否组合,都会遵循如下规则:


这里需要补充说明的是:因为对于范围查询,都会有个边界,所以如果没有任何匹配,就会只对边界加锁,规则不变!

结论开篇就给出了,结论传送门.

如果感觉不错,请收藏本专栏,后面还有更详细的锁机制陆续放出。
关注我 天罡gg 分享更多干货: https://blog.csdn.net/scm_2008
大家的「关注 + 点赞 + 收藏」就是我创作的最大动力!谢谢大家的支持,我们下文见!

来源地址:https://blog.csdn.net/scm_2008/article/details/128272465

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯