SQL语句加锁分析

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介:

SQL语句加锁分析

背景
MySQL中SQL加锁的情况十分复杂,不同隔离级别、不同索引类型、索引是否命中的SQL加锁各不相同。
然而在分析死锁过程当中,熟知各种情况的SQL加锁是分析死锁的关键,因此需要将MySQL的各种SQL情况加锁进行分析总结。

基础知识
MVCC
快照读
读取历史版本,从undo log中读取行记录的快照;这样读行就不需要等待锁资源,提高了并发;
当前读
读取最新版本,并且当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
加锁读、插入、更新、删除等操作均属于当前读

将插入,更新,删除归为当前读是因为这些操作均包含读取当前记录的操作。拿update table set ? where ?来讲,
当Update SQL被发给MySQL后,MySQL Server会根据where条件,读取第一条满足条件的记录,然后InnoDB引擎会将第一条记录返回,并加锁 (current read)。
待MySQL Server收到这条加锁的记录之后,会再发起一个Update请求,更新这条记录。一条记录操作完成,再读取下一条记录,直至没有满足条件的记录为止。
因此,Update操作内部,就包含了一个当前读。同理,Delete操作也一样。Insert操作会稍微有些不同,简单来说,就是Insert操作可能会触发Unique Key的冲突检查,也会进行一个当前读。

注意:
Innodb当前读加锁是一条一条进行,先对一条满足条件的记录加锁,返回给MySQL Server做一些DML操作,然后在读取下一条加锁,直至读取完毕。

Two-phase locking
Two-Phase Locking,说的是锁操作分为两个阶段:加锁阶段与解锁阶段,并且保证加锁阶段与解锁阶段不相交。 加锁阶段:只加锁,不放锁。解锁阶段:只放锁,不加锁。

隔离级别

数据库的隔离现象与隔离级别如下图所示
 

脏读现象:即A连接,未提交的事务,B连接的事务可以看到;

NONREPEATABLE READ(不可重复读)现象:
A连接,提交的事务,B连接的事务中可以看到,这样在B连接中的事务,就可以看到A连接事务提交前,和提交后两种状态;
注意:不可重复读针对update,delete

PHANTOM READ(幻读)现象:
A连接,提交的事务,B连接的事务可以看到,这样在B连接中的事务,就可以看到A连接事务提交前,和提交后两种状态;
注意:幻读针对insert;

innodb事务引擎,通过间隙锁 粗暴 将RR隔离级别的幻读现象消除,这也是RR与RC的主要区别。

基础SQL组合分析
使用下面这张 students 表作为实例,其中 id 为主键,no(学号)为二级唯一索引, score(学分)为二级非唯一索引,age(年龄)无索引。

我们只分析基础SQL,它只包含一个 WHERE 条件,等值查询或范围查询,根据条件类型以及隔离级别不同(主要分析最常用的RR,RC)我们主要分析一下情况:

聚簇索引,索引命中
SQL select * from students where id = 20  for update,  在 RC 和 RR 隔离级别下加锁情况一样,都是对 id 这个聚簇索引加 X 锁,如下:

唯一索引,索引命中
SQL:select * from students where num = 135 for update;
若检索唯一索引,那么SQL需要加两个X锁,一个对应唯一索引上的num = 135的记录,另一把锁对应于聚簇索引上的[id=35]的记录。

二级索引,索引命中
SQL:select * from students where score= 91  for update;
如此例子当中如法插入score 值有[77,99),注意边界值。前边界77是无法插入的,后边界99则可以插入。
此外 select * from students where score= 77  for update,是不用等待锁的。

无索引

SQL: select * from students where age = 22  for update;
无索引时如何是RR还是RC均会将行锁升级为表锁,具体表现就是全表update,delete。
此外因为RR隔离级别有next-key,RR除了不能update,delete外连insert都不可以,而RC则可以进行insert 操作。

索引未命中

聚簇索引,索引未命中
SQL  select * from students where id = 30  for update;
RR隔离级别下,当查找聚簇索引但索引未命中时,此时聚簇索引加锁状态与二级索引状态相同,原本行锁变为gap锁,锁范围如下:
(25,35)
当然此时收主键唯一性约束,任何插入id=25或35的操作均会失败,这一点与二级索引不同。
RC隔离级别下,由于id索引未命中即聚簇索引中没有相关记录,则不加任何锁。

唯一索引,索引未命中
SQL  select * from students where num = 130  for update;
唯一索引,索引未命中的情况与上面聚簇索引,索引未命中的情况 相似。区别在于聚簇索引gap锁加载聚簇表中,唯一索引则在唯一索引自身的索引表中。
同样是没有行锁,仅有gap锁,其表现出来的现象就是在gap范围内如法插入数据,不影响其余DML操作。

二级索引,索引未命中
SQL  select * from students where score = 70  for update;

范围查询
聚簇索引范围查询
select * from students where id <=25 for update;
RR隔离级别时,聚簇索引范围查询时加锁情况如下图。
如果where 条件为id<25 则在25-35间不会加GAP锁,但也会在25上加X锁,然后再在相应范围加GAP锁。
如果where 条件为id>25,并不会在25处加X锁,仅会在(25,+)加GAP锁以及对应索引项加X锁。

注意:在RR隔离级别时,条件y

唯一索引范围查询
select * from students where num >125 for update;
唯一索引范围查询整体与聚簇索引范围查询相似,RC仅在范围内的索引列上加X锁。RR则除在索引列上在X锁外,还会在范围内索引列之间加GAP锁。
此外RR的边界值是否加X锁,有向右扩展原则即向索引值大的方向扩展加X锁。当num<125时,向右扩展的第一个索引值为125 则会在125上加X锁。
当num<=125时,向右扩展的第一个索引值为135,则会在135上加X锁。当num>125时,向右扩展的第一个索引值为135,包含在范围之内因此无特殊表现。

二级索引范围查询
select * from students where score <= 50 for update;
由下图可见二级索引范围查询其实与唯一索引以及聚簇索引的范围查询的加锁原理相同。RC仅在范围内的索引项上加X锁。
RR则除范围内索引项加X锁外,并在索引项间加GAP锁,且边界值是否加X锁遵循向右扩展原则。

小结
索引等值查询,且索引命中
主键、唯一索引无论RR或RC均在索引项及其聚簇索引对应记录上加X锁。
二级索引RC隔离级别与主键、唯一索引相同
二级索引RR隔离级别,除对应索引项及其记录上加X锁外,在各索引项间加GAP锁
索引等值查询,且索引未命中
RR主键,与唯一索引会在包含条件值得两个索引项间 加GAP锁
二级索引与主键、唯一索引相似,也会在包含条件值的两个索引间加GAP锁并在左侧索引项上加X锁
RC不加任何锁
索引范围查询
主键索引,唯一索引,二级索引加锁原理相同。
RC仅在范围内的索引项上加X锁。
RR则除范围内索引项加X锁外,并在索引项间加GAP锁,且边界值是否加X锁遵循向右扩展原则

另一个角度总结
RC
RC隔离级别没有GAP锁(唯一索引insert情况除外,仅指select情况),仅在符合条件的索引项上加X锁
RR
RR隔离基本多了GAP锁,但在主键或唯一索引存在时仅在索引项及其记录上加X锁,不加GAP锁。
二级锁索引则除索引项及其记录上加X锁外,并在包含X锁记录的两侧索引项之间加GAP锁。
若索引值未命中
主键,唯一索引,二级索引均会在包含未命中索引值得两侧索引项之间加GAP锁。
若是二级索引还会在左侧索引项上加X锁。

where 条件提取

给定一条SQL,索引项是如何影响查询过程的,非索引项的条件是如何过滤数据,只有清楚掌握每个细节才能写出性能较高的SQL语句。
SQL的where条件大约分为3类
index key
index filter
table filter

Index Key
确定索引扫描的范围,其包括起始位置与终止位置, 因此Index Key也被拆分为Index First Key和Index Last Key,
分别用于定位索引查找的起始,以及索引查询的终止条件。

Frist Key
用于确定索引查询的起始范围。
提取规则:从索引的第一个键值开始,检查其在where条件中是否存在,若存在并且条件是=、>=,则将对应的条件加入Index First Key之中,继续读取索引的下一个键值,使用同样的提取规则;若存在并且条件是>,则将对应的条件加入Index First Key中,同时终止Index First Key 提取;若不存在,同样终止Index First Key 提取。

例如
idx_c1_c2_c3(c1,c2,c3)
where c1>=1 and c2>2 and c3=1
-->  first key (c1,c2)
--> c1为 '>=' ,加入下边界界定,继续匹配下一个
--> c2 为 '>', 加入下边界界定,停止匹配

Last Key
用于确定索引查询的终止范围.
提取规则:从索引的第一个键值开始,检查其在where条件中是否存在,若存在并且条件是=、<=,则将对应条件加入到Index Last Key中,继续提取索引的下一个键值,使用同样的提取规则;若存在并且条件是 < ,则将条件加入到Index Last Key中,同时终止提取;若不存在,同样终止Index Last Key的提取。

例如
idx_c1_c2_c3(c1,c2,c3)
where c1<=1 and c2=2 and c3<3
--> last key (c1,c2,c3)
--> c1为 '<=',加入上边界界定,继续匹配下一个
--> c2为 '='加入上边界界定,继续匹配下一个
--> c3 为 '<',加入上边界界定,停止匹配

注意:提取过程中 如果比较符号中包含'='号,'>='也是包含'=',那么该索引键是可以被利用的,可以继续匹配后面的索引键值;如果不存在'=',也就是'>','<',这两个,后面的索引键值就无法匹配了。

Index Filter
字面理解就是可以用索引去过滤。也就是字段在索引键值中,但是无法用去确定Index Key的部分。

exp:
idex_c1_c2_c3
where c1>=1 and c2<=2 and c3 =1
index key --> c1
index filter--> c2 c3

这里为什么index key 只是c1呢?因为c2 是用来确定上边界的,但是上边界的c1没有出现(<=,=),而下边界中,c1是>=,c2没有出现,因此index key 只有c1字段。c2,c3 都出现在索引中,被当做index filter.

MySQL 是 5.6 之前的版本,Index Filter 和 Table Filter 没有区别,统统将 Index First Key 与 Index Last Key 范围内的索引记录,回表读取完整记录,然后返回给 MySQL Server 层进行过滤。而在 MySQL 5.6 之后,Index Filter 与 Table Filter 分离,Index Filter 下降到 InnoDB 的索引层面进行过滤,减少了回表与返回 MySQL Server 层的记录交互开销,提高了SQL的执行效率,这就是 ICP(Index Condition Pushdown)。

Table Filter
无法利用索引完成过滤,就只能用table filter。此时引擎层会将行数据返回到server层,然后server层进行table filter。

举例来说

Index Key  : pubtime
Index Filter:   userid
Table Filter:   comment

若使用5.6之前的版本则红色箭头线所指的记录会加X锁,因为5.6之前Index Filter与Table Filter作用一样,都需要根据Index Key 的扫描范围回表,到server层再过滤。
若使用5.6及其之后的版本则红色箭头线缩指的记录不会加X锁,因为ICP(Index Condition Pushdown)特性,在Index Key 扫描完范围后,根据Index Filter过滤掉不符合要求的然后在回表到server层去过滤Table Filter 即找到comment not  null的记录在该条记录上加X锁。
原文地址https://www.cnblogs.com/Aiapple/p/12751803.html

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
SQL 索引
19. 一个SQL语句执行很慢, 如何分析
该内容介绍了如何分析执行慢的SQL语句。首先启用慢查询日志或使用命令获取慢查询的SQL。然后利用`EXPLAIN`命令分析,关注其中的`select_type`, `type`, 和 `extra`字段。`select_type`涉及子查询和联合查询的类型,`type`表示查询优化器使用的访问类型,性能从上到下递减,`extra`字段提供额外信息,如是否使用索引等。
48 0
|
1月前
|
SQL 存储 数据可视化
手机短信SQL分析技巧与方法
在手机短信应用中,SQL分析扮演着至关重要的角色
|
6月前
|
SQL 数据可视化 算法
SQL Server聚类数据挖掘信用卡客户可视化分析
SQL Server聚类数据挖掘信用卡客户可视化分析
|
3月前
|
前端开发 Java JSON
Struts 2携手AngularJS与React:探索企业级后端与现代前端框架的完美融合之道
【8月更文挑战第31天】随着Web应用复杂性的提升,前端技术日新月异。AngularJS和React作为主流前端框架,凭借强大的数据绑定和组件化能力,显著提升了开发动态及交互式Web应用的效率。同时,Struts 2 以其出色的性能和丰富的功能,成为众多Java开发者构建企业级应用的首选后端框架。本文探讨了如何将 Struts 2 与 AngularJS 和 React 整合,以充分发挥前后端各自优势,构建更强大、灵活的 Web 应用。
58 0
|
3月前
|
SQL 数据采集 数据挖掘
为什么要使用 SQL 函数?详尽分析
【8月更文挑战第31天】
50 0
|
3月前
|
SQL 数据采集 算法
【电商数据分析利器】SQL实战项目大揭秘:手把手教你构建用户行为分析系统,从数据建模到精准营销的全方位指南!
【8月更文挑战第31天】随着电商行业的快速发展,用户行为分析的重要性日益凸显。本实战项目将指导你使用 SQL 构建电商平台用户行为分析系统,涵盖数据建模、采集、处理与分析等环节。文章详细介绍了数据库设计、测试数据插入及多种行为分析方法,如购买频次统计、商品销售排名、用户活跃时间段分析和留存率计算,帮助电商企业深入了解用户行为并优化业务策略。通过这些步骤,你将掌握利用 SQL 进行大数据分析的关键技术。
182 0
|
3月前
|
SQL 数据挖掘 BI
【超实用技巧】解锁SQL聚合函数的奥秘:从基础COUNT到高级多表分析,带你轻松玩转数据统计与挖掘的全过程!
【8月更文挑战第31天】SQL聚合函数是进行数据统计分析的强大工具,可轻松计算平均值、求和及查找极值等。本文通过具体示例,展示如何利用这些函数对`sales`表进行统计分析,包括使用`COUNT()`、`SUM()`、`AVG()`、`MIN()`、`MAX()`等函数,并结合`GROUP BY`和`HAVING`子句实现更复杂的数据挖掘需求。通过这些实践,你将学会如何高效地应用SQL聚合函数解决实际问题。
51 0
|
3月前
|
网络协议 NoSQL 网络安全
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
|
4月前
|
SQL 运维 监控
MSSQL性能调优实战:索引策略优化、SQL查询重写与智能锁管理
在Microsoft SQL Server(MSSQL)的运维中,性能调优是确保数据库高效运行、满足业务需求的关键环节
|
4月前
|
SQL 监控 数据库
MSSQL性能调优秘籍:索引深度优化、SQL重构技巧与高效锁策略
在Microsoft SQL Server(MSSQL)环境中,性能调优是确保数据库高效运行、满足业务快速增长需求的关键