next-key lock的规则

本文详细解析了MySQL InnoDB的锁机制,重点介绍了Next-Key Lock、行锁、Gap Lock以及不同版本的差异。通过多个案例分析了等值查询、范围查询在不同场景下的加锁范围,包括正序和倒序排序的影响,揭示了锁的适用性和优化策略。

背景

参考:https://blog.youkuaiyun.com/wanger61/article/details/107817158
MySQL 后面的版本可能会改变加锁策略,所以这个规则只限于截止到现在的最新版本,即 5.x 系列<=5.7.24,8.0 系列 <=8.0.1,实验发现不同版本的差异主要是:索引范围查询的临界值的取舍有所不同。8.0范围查询加锁不包含临界值,7.0范围查询加锁包含临界值。

Net-Key Lock的规则

原则 1:加锁的基本单位是 next-key lock。next-key lock 是前开后闭区间。
原则 2:只有访问到的对象才会加锁。
优化 1:索引上的等值查询,
    命中唯一索,退化为行锁。
    命中普通索引,左右两边的GAP Lock + Record Lock。
优化 2:
    索引上的等值查询,未命中,所在的Net-Key Lock,退化为GAP Lock 。
索引在范围查询: 
    1.等值和范围分开判断。
    2.索引在范围查询的时候 都会访问到所在区间不满足条件的第一个值为止。
    3.如果使用了倒叙排序,按照倒叙排序后,
    检索范围的右边多加一个GAP。
    哪个方向还有命中的等值判断,再向同方向拓展外开里闭的区间。

构造数据

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `c` (`c`)
) ENGINE=InnoDB;

insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);

案例1

image.png

分析:

  1. 根据原则1,加锁都是net-key lock,所以id=7时所在的Net-Key Lock是(5,10]。
  2. 根据优化2,等值查询且未命中表中的一行数据,所以next-key lock退化成GAP lock (5,10)
  3. 所以最后锁的区间是(5,10)。

案例2

image.png

分析:

  1. 根据优化1,c普通索引,加的是锁(0,5)+5+(5,10)
  2. 根据原则 2 ,只有访问到的对象才会加锁,这个查询使用覆盖索引,并不需要访问主键索引,所以主键索引上没有加任何锁,这就是为什么 session B 的 update 语句可以执行完成。
  3. 所以最后的锁范围是(0,10)。

案例3

image.png

分析:

  1. 索引范围查询,等值和范围分开判断。所以对10 < c < 11 和 c = 10分别判断。
  2. 范围查询 10 < c < 11,在c的范围内在的Net-Key Lock是(10,15]。拿所在区间内不满足条件的第一个值,作为加锁范围的临界值。10和15是区间中第一个不满足条件10 < c < 11的值,所以锁定的范围是(10,15]。
  3. 等值查询 c = 10,c是普通索引,所以根据优化2,锁的范围是(5,10)+10+(10,15).。
  4. 所以把上面两种情况合起来锁的范围就是(5,15]。

注意:

刚才是mysql7.0版本所以范围查询锁定的区间是(10,15]。如果是8.0范围查询锁定的是(10,15)。区别在于范围查询加锁的时候7.0版本加的是next-key lock。8.0版本范围查询加锁加的是GAP Lock。

案例4

select * from t where id>10 and id<=15 order by id desc for update;

分析:

倒排序后是:20 , 15 , 10 , 5 , 0

  1. 按照倒叙排序后,查询范围是 10<c<15 , 所以锁的范围是(15,10]。
  2. 按照倒叙排序后,检索范围的右边多加一个GAP区间。所以加一个(10,5)。
  3. 哪边还有命中的等值判断,再向同方向拓展外开里闭的区间。15在左边且有等值命中,所以再向同方向拓展一个外开里闭区间(20,15]。
  4. 唯一索引等值查询。id =15命中退化成Record Lock。
  5. 所以上面所有的范围是:(20,15] + 15 + (15,10] + (10,5)。
    最终加锁范围是:(20,5)

案例5

select * from t where id>=10 and id<15 order by id desc for update;

分析:

倒排序后是:20 , 15 , 10 , 5 , 0

  1. 按照倒叙排序后,查询范围是 10<c<15 , 所以锁的范围是(15,10]。
  2. 按照倒叙排序后,检索范围的右边多加一个GAP区间。所以加一个(10,5)。
  3. 哪边还有命中的等值判断,再向同方向拓展外开里闭的区间。10在右边且有等值命中,再向同方向拓展外开里闭的区间,因为已经加了一个(10,5),所以在原基础上再向右推展一个外开里闭区间[5,0)。
  4. 唯一索引等值查询。id =15命中退化成Record Lock。
  5. 所以上面所有的范围是:(15,10] + (10,5) + [5,0)。
    最终加锁范围是:(15,0)
<think>好的,我现在需要回答用户关于MySQL中页级Next-Key Lock的区别及应用场景的问题。首先,我需要明确这两个概念的定义和它们在InnoDB中的角色。 首先,页级,根据我之前学过的知识,页级MySQL中一种定机制,定整个数据页。数据页是InnoDB存储数据的基本单位,通常大小为16KB。页级的粒度介于表和行之间,它会影响整个页内的所有行,即使只访问其中一行。这种的优点是开销比行小,冲突概率比表低,但缺点是不够精细,可能导致不必要的定,影响并发性能。应用场景可能是在需要平衡并发和开销的情况下,比如批量更新同一页内的多行数据时。 然后是Next-Key Lock,这是InnoDB为了实现可重复读隔离级别而设计的机制,结合了记录(行)和间隙Next-Key Lock定的是索引记录之间的间隙以及记录本身,防止幻读的发生。例如,当查询某个范围的数据时,Next-Key Lock定这个范围以及相邻的间隙,确保其他事务不能插入新的数据到这个范围内。根据引用[4]提到的加规则Next-Key Lock是前开后闭区间,并且在某些情况下会退化为行或间隙。 接下来,我需要区分两者的区别。首先是的粒度:页级定整个页,而Next-Key Lock定的是索引记录和间隙,属于行级的范畴。的用途方面,页级用于控制对物理页的访问,而Next-Key Lock用于解决幻读问题,保证事务的隔离性。在并发控制上,页级可能因为住更多数据而导致并发度较低,而Next-Key Lock虽然更精细,但由于需要维护更多,可能有更高的开销。应用场景方面,页级适合批量操作同一页的数据,而Next-Key Lock用于需要防止幻读的高并发事务环境。 还需要考虑用户提供的引用内容。引用[1]提到InnoDB的三种行:间隙、行Next-Key Lock,说明Next-Key Lock属于行级的一部分。引用[4]详细说明了Next-Key Lock的加规则,包括退化为行或间隙的情况,这有助于解释其灵活性。而页级并不属于行,是另一种粒度的,可能在较早的MySQL版本或特定场景中使用较多,但现在InnoDB默认使用行级Next-Key Lock来实现更高并发。 用户可能混淆了不同粒度的,需要明确页级和行级(包括Next-Key Lock)的不同层级。此外,应用场景的对比需要具体举例,比如页级在批量处理时的效率,而Next-Key Lock在事务安全中的重要性。 最后,确保回答结构清晰,分点说明概念、区别、应用场景,并生成相关问题。同时检查是否需要引用,比如引用[4]提到的加规则,可以在解释Next-Key Lock时引用。</think>### 页级Next-Key Lock的概念及区别 #### 一、基本概念 1. **页级** - **定义**:定InnoDB存储引擎中的物理数据页(默认16KB),属于中粒度- **特点**:无论访问页内多少行数据,都会定整个页。 - **应用场景**:适用于批量操作同一页内多行数据的场景(如旧版本MySQL的特定优化)。 2. **Next-Key Lock** - **定义**:InnoDB在可重复读(Repeatable Read)隔离级别下使用的机制,**结合记录(行)和间隙**,防止幻读[^2][^4]。 - **特点**: - 定范围:索引记录本身(行) + 索引前的间隙(间隙),形成**前开后闭区间**,例如`(5, 10]`[^4]。 - 根据查询条件可能退化为**行**(唯一索引等值查询)或**间隙**(非唯一索引等值查询)[^4]。 --- #### 二、核心区别 | **维度** | **页级** | **Next-Key Lock** | |-------------------|--------------------------------|-----------------------------------| | **粒度** | 物理页(16KB) | 索引记录及间隙(行级范畴) | | **目标** | 控制物理页的并发访问 | 解决幻读,保证事务隔离性 | | **并发性能** | 较低(定更多数据) | 较高(更精细,但数量可能更多) | | **应用场景** | 批量操作同一页数据 | 高并发事务中防止幻读 | | **实现层级** | 存储引擎物理层 | 索引逻辑层 | --- #### 三、应用场景 1. **页级** - **适用场景**: - 历史版本MySQL中需要平衡开销与并发性能的场景。 - 批量更新或删除同一页内的连续数据(如日志表清理)。 - **局限性**:现代InnoDB默认使用行级,页级逐渐被替代。 2. **Next-Key Lock** - **适用场景**: - 事务需要避免幻读(如银行转账、库存扣减)。 - 范围查询(`WHERE id BETWEEN 10 AND 20`)或非唯一索引的等值查询。 - **示例**: ```sql -- 对索引列age=20的查询会定(15,20]的Next-Key Lock SELECT * FROM users WHERE age = 20 FOR UPDATE; ``` --- #### 四、总结对比 - **页级**关注**物理存储单元**的并发控制,适合**粗粒度操作**。 - **Next-Key Lock**关注**逻辑数据一致性**,通过精细的行级实现事务安全。 - **现代InnoDB更依赖Next-Key Lock**,因其能有效支持高并发事务场景。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值