[英]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.