创建两个表格进行比较:
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锁定模型的理解,为什么tx1
要锁定表t1
中的每个索引记录?
===============更新================
现在使用explain,我看到了一些不同之处:
===============更新2 ================
正如@Bill Karwin的回答所指出的,type: index
意味着扫描整个索引树,参见ref连接类型。
但是,如果我再插入一行:insert into t1 values (12)
,则连接类型更改为type: range
,并且不会锁定所有索引记录!
我猜mysql源代码中有一些内部怪癖。
1条答案
按热度按时间63lcw9qa1#
检查的所有行都被锁定。
答案在EXPLAIN报告中。执行
type: index
的查询是在执行索引扫描,它检查索引的每个成员。对于PRIMARY索引,这实际上检查了整个表。执行
type: range
的查询正在检查行的子集。优化器出于某种原因选择进行索引扫描。我不确定确切的原因。这可能取决于您使用的MySQL版本。您可以使用以下查询进行检查:
SELECT VERSION();
我相信当这个查询是一个覆盖索引时,它被当作一个索引扫描来处理。这就是解释注解“使用索引”。如果查询获取的列与索引中的列相同,那么它就是一个覆盖索引。
如果测试以下查询,您将获得相同的优化策略(索引扫描):
因为
id
是主键索引的列,并且是查询返回的唯一列。