背景

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<id<x, 则MySQL选择比y,x大的索引项来加X锁,称为向右扩展
 
 
  • 唯一索引范围查询

    • 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锁。 

SQL语句加锁分析的更多相关文章

  1. MySQL innodb中各种SQL语句加锁分析

    概要 Locking read( SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),UPDATE以及DELETE语句通常会在他扫描的索引所 ...

  2. MySQL中一条SQL的加锁分析

    MySQL中一条SQL的加锁分析 id主键 + RC id唯一索引 + RC id非唯一索引 + RC id无索引 + RC id主键 + RR id唯一索引 + RR id非唯一索引 + RR id ...

  3. SQL语句性能分析

    SQL语句性能分析 explain执行计划 用法: explain select 语句 命令: show database; use mysql explain select * from user; ...

  4. 看懂SqlServer查询计划 SQL语句优化分析

    转自 http://www.cnblogs.com/fish-li/archive/2011/06/06/2073626.html 阅读目录 开始 SQL Server 查找记录的方法 SQL Ser ...

  5. SQL语句优化分析

    分析比较执行时间计划读取情况 select * from dbo.Product 执行上面语句一般情况下只给你返回结果和执行行数,那么你怎么分析呢,怎么知道优化之后跟没有优化的区别呢. 下面几种方法: ...

  6. SQL 语句 explain 分析

      分析索引的效率: > EXPLAIN sql; EXPLAIN 分析的结果的表头如下: id | select_type | table | partitions | type | poss ...

  7. SQL语句性能分析常用命令

    DBCC freeproccache DBCC dropcleanbuffers 1.set statistics IO {ON| OFF} /*Transact-SQL 语句生成的磁盘活动量的信息* ...

  8. 查看sql语句加锁信息

    问题: 最近使用quartz集群,总是报deadlock问题,所以需要查看一下执行的sql导致的加锁冲突. 步骤: 1.在要测试的库中创建指定表innodb_lock_monitor create t ...

  9. 历史执行Sql语句性能分析 CPU资源占用时间分析

    SELECT     HIGHEST_CPU_QUERIES.PLAN_HANDLE,     HIGHEST_CPU_QUERIES.TOTAL_WORKER_TIME,     Q.DBID,   ...

随机推荐

  1. hdu2732 最大流+拆点

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2732 题目给定一个场景,有n*m个方格,每个方格代表一个柱子,一个柱子可以承受不同次数的跳跃,开始时图 ...

  2. vue采坑记录

    1.项目在浏览器运行的时候没有ico图标 <link rel="shortcut icon" type="image/x-icon" href=" ...

  3. C#中的9个“黑魔法”与“骚操作”

    C#中的9个"黑魔法"与"骚操作" 我们知道C#是非常先进的语言,因为是它很有远见的"语法糖".这些"语法糖"有时过于好 ...

  4. AI领域:如何做优秀研究并写高水平论文?

    来源:深度强化学习实验室 每个人从本科到硕士,再到博士.博士后,甚至工作以后,都会遇到做研究.写论文这个差事.论文通常是对现有工作的一个总结和展示,特别对于博士和做研究的人来说,论文则显得更加重要. ...

  5. Codeforces 631 (Div. 2) D. Dreamoon Likes Sequences 位运算^ 组合数 递推

    https://codeforces.com/contest/1330/problem/D 给出d,m, 找到一个a数组,满足以下要求: a数组的长度为n,n≥1; 1≤a1<a2<⋯&l ...

  6. C 怪兽游戏

    时间限制 : - MS   空间限制 : - KB  评测说明 : 1s,256m 问题描述 何老板在玩一款怪兽游戏.游戏虽然简单,何老板仍旧乐此不疲.游戏一开始有N只怪兽,编号1到N.其中第i只怪兽 ...

  7. Spring Boot 完整讲解

    SpringBoot学习笔记 文章写得比较详细,所以很长(105336 字数),可以参考目录 文章目录 SpringBoot学习笔记 @[toc] 一. Spring Boot 入门 预:必须掌握的技 ...

  8. MySQL入门,第三部分,学会添加删除数据库

    一.建立数据库 create database [if not exists] database_name [create_specification] 注意: 1.if not exists === ...

  9. 路由与交换,cisco路由器配置,静态路由

    网络是一个大型的拓扑结构,在路由表中,最重要的是管理距离和度量值 管理距离 管理距离用来确定路由的优先级.管理距离的范围是0-255之间的整数值.值越低代表优先级越高.0代表最高优先级.并且只有直连路 ...

  10. Linux 磁盘管理篇,连接文件

    连接文件分为两种 1.像Window类似的快捷方式的文件 2.通过文件系统的inode来产生新的文件名而不是新文件(硬连接) 创建连接文件            ln 创建连接文件的快捷方式      ...