Mysql普通索引和唯一索引触发next-key和行锁的时机总结

本文详细介绍了MySQL中普通索引和唯一索引在不同查询条件下触发Next-Key Lock和行锁的情况。在RR隔离级别下,普通索引遵循'锁左不锁右'原则,而唯一索引则是'锁右不锁左'。文章通过实例测试,解析了各种比较操作下的锁定范围,帮助读者深入理解这两种索引的锁行为。

最近学完next-key,有点搞不清什么时候会使用next-key,什么时候会降级为行锁,所以测试了一下,归纳一下。

普通索引参考的文章:
MySQL使用普通索引检索时产生的next-key lock和gap lock的范围测试
想要自己测试的朋友可以参考一下改文章的做法。

本文用的数据以10为间隔,[0,100]。
测试环境:
RR可重复读级别下,会触发next-key lock ,
即以下这些情况 ,本文统一以"查询"为例,但其他操作都是一样的

select .. for update
select .. in share mode
update
insert
delete

至于无索引、索引失效的情况,本文不讨论,那些都是转为表锁的。

先说个总的结论:
普通索引是锁左不锁右,即[a,b)
而唯一索引则相反, 锁右不锁左 ,即(a,b]

普通索引

  1. =

    普通索引的处理比较简单:

    假设= x无论x这条记录是否存在表中,都是锁上相邻记录

    这里的相邻记录,指的是两端的记录,

    eg: x=10 , 表中上一条记录为0, 下一条记录为20,锁上 [0,20)

    注意,这里**右端是取不到的**,本文称之为"锁左不锁右"

    # 事务1查询条件 事务2被阻塞的锁定范围
    1 x=10 [0, 20)
    2 x=13 [10, 20)

    所以操作x=20的数据,比如插入或者删除,都是不会阻塞的

  2. in

    其实in所做的操作就是把每个值,作为单独的一个等值查询操作,再把产生的锁定范围取并集

    eg: x in (a,b) , 等价于 (x = a) U (x=b)

    # 事务1查询条件 事务2被阻塞的锁定范围
    3 j in(10, 40) [0, 20) union [30, 50)
    4 j in(10, 45) [0, 20) union [40, 50)
    5 j in(15, 40) [10, 20) union [30, 50)
    6 j in(15, 45)
<think>我们正在讨论MySQL中的机制,特别是当查询不走索引时是否会加间隙。根据提供的引用内容,我们可以得出以下结论: 1. **引用[2]中提到**:无索引为表。这意味着当查询条件没有使用索引时,MySQL会将为表,以避免对每都加带来的性能开销。因此,在这种情况下,不会产生间隙(因为整个表被住了)。 2. **引用[3]中提到**:间隙临键是在可重复读隔离别下为了解决幻读问题而引入的。但是,这些的加为依赖于索引。如果没有索引MySQL可能会退化为表。 3. **引用[4][5]中提到**:间隙(Gap Lock)的目的是阻止其他事务在间隙中插入数据。但是,当查询没有使用索引时,MySQL无法确定具体的间隙,因此无法使用间隙。相反,它会使用表来保证数据的一致性。 因此,结论是:**当查询不走索引时,MySQL不会加间隙,而是会将为表**。这样做是为了避免对大量无索引的数据,从而减少的开销。但是,表会降低并发性能,因为整个表被定,其他事务无法修改表中的任何数据。 下面我们通过一个例子来说明: 假设有一个表`lock_test`,其中有一个非索引列`a`。执以下查询: ```sql SELECT * FROM lock_test WHERE a = 3 FOR UPDATE; ``` 由于`a`列没有索引MySQL无法使用或间隙定特定的或间隙。因此,MySQL会将整个表住(表),以防止其他事务修改表中的任何数据。 **注意事项**: - 在可重复读(Repeatable Read)隔离别下,如果查询使用了索引MySQL会使用间隙临键来防止幻读。 - 在读已提交(Read Committed)隔离别下,间隙会被禁用,因此不会使用间隙。 **总结**: - 使用索引MySQL会使用、间隙临键(取决于查询条件隔离别)。 - 不使用索引MySQL会将为表,因此不会使用间隙。 希望这个解释对您有帮助! §§相关问题§§ 1. 如何避免MySQL中的为表? 2. 在哪些情况下,即使使用了索引MySQL仍然可能使用表? 3. 如何查看MySQL中的信息?</think>### MySQL 不走索引时的机制分析 #### 核心结论 **当查询不走索引时,MySQL 会将为表,不会产生间隙(Gap Lock)或临键Next-Key Lock)**[^2][^3]。 #### 机制详解 1. **无索引时的** - **退化为表**:若 `WHERE` 条件未命中索引MySQL 无法精确定位数据,为避免全表扫描带来的开销,会直接将**为表**。此时整个表被定,其他事务无法修改任何数据[^2][^3]。 - **间隙失效**:间隙依赖索引定位数据间隙。无索引时,MySQL 无法确定间隙范围,因此**不会生成间隙或临键**[^3][^5]。 2. **示例场景对比 ```sql -- 场景1:使用索引(假设 a 是索引列) SELECT * FROM table1 WHERE a = 3 FOR UPDATE; --(主键)+ 临键/间隙(非主键索引)[^1][^4] -- 场景2:无索引(假设 a 无索引) SELECT * FROM table1 WHERE a = 3 FOR UPDATE; --:表(整个表被定)[^2][^3] ``` - **无索引下的操作阻塞**: - 其他事务的 `INSERT/UPDATE/DELETE` 操作会被阻塞(表生效)。 - 普通 `SELECT` 可正常读取(表不阻塞读),但 `SELECT ... FOR UPDATE` 或 `LOCK IN SHARE MODE` 会被阻塞[^4]。 3. **隔离别的影响** - **可重复读(RR)**:无索引时直接退化为表[^2][^3]。 - **读已提交(RC)**:间隙被禁用,无索引查询可能退化为表或仅加行(取决于优化器)[^5]。 #### 性能与风险 - **缺点**:表严重降低并发性,高并发场景易导致超时(`Lock wait timeout`)[^2][^4]。 - **优化建议**: 1. 为查询条件添加索引,避免。 2. 避免长事务,减少持有时间。 3. 监控争用:通过 `SHOW ENGINE INNODB STATUS` 或 `information_schema.INNODB_TRX` 分析状态[^3]。 --- ### 总结 | **场景** | **** | **间隙/临键** | **表** | |----------------|----------|-------------------|----------| | **使用索引** | ✅ | ✅(RR隔离别) | ❌ | | **无索引** | ❌ | ❌ | ✅ | > 关键点:**无索引查询会触发,间隙仅在索引查询时生效**。
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值