繁体   English   中英

为什么在 mysql 中只有一个索引列时,使用范围条件锁定读取会锁定每条记录?

[英]why locking read with range condition locks every record when there is only one index column in mysql?

创建两个表进行比较:

create table t1(id integer primary key);
create table t2(id integer primary key, num integer);
insert into t1 values (0),(3),(6),(9);
insert into t2 values (0, 0), (3, 3), (6, 6), (9, 9);

启动事务tx1并对表t1进行锁定读取:

start transaction;
select * from t1 where id >=3 and id < 8 for update;

tx1持有的锁如下所示:

在此处输入图像描述

现在回滚tx1 ,启动事务tx2并对表t2进行锁定读取:

start transaction;
select * from t2 where id >=3 and id < 8 for update;

tx2持有的锁如下所示:

在此处输入图像描述

tx2的行为符合我对mysql加锁model的理解。为什么tx1会加锁表t1的每条索引记录?

================更新==================

现在使用解释我看到了一些差异:

在此处输入图像描述

================ 更新 2 ==================

正如@Bill Karwin 的回答指出的那样, type: index表示扫描整个索引树,请参阅 ref join-types

但是,如果我再插入一行: insert into t1 values (12) ,连接类型将更改为type: range并且它不会锁定所有索引记录!

在此处输入图像描述

我猜 mysql 源代码中有一些内部怪癖。

所有被检查的行都被锁定。

答案在 EXPLAIN 报告中。 执行type: index的查询正在执行索引扫描,检查索引的每个成员。 在 PRIMARY 索引的情况下,这有效地检查了整个表。

执行type: range的查询正在检查行的子集。

出于某种原因,优化器选择进行索引扫描。 我不确定到底是为什么。 这可能取决于您使用的 MySQL 的版本。 您可以检查此查询: SELECT VERSION();


我相信这个查询在覆盖索引时被视为索引扫描。 那就是说明“使用索引”的说明说明。 如果查询获取的列与索引中的列相同,则它是一个覆盖索引。

如果您测试此查询,您将获得相同的优化策略(索引扫描):

select id from t2 where id >=3 and id < 8 for update;

因为id是主键索引的列,而且它是查询返回的唯一列。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM