这是一些伪SQL,其中很容易复制“问题”:
create table Child (
childId text primary key,
some_int int not null
);
create table Person (
personId text primary key,
childId text,
foreign key (childId) references Child (childId) on delete cascade
);
create index Person_childId on Person (childId);
explain query plan select count(1)
from Person
left outer join Child on Child.childId = Person.childId
where Person.childId is null or Child.some_int = 0;查询计划的结果是:
SCAN Person USING COVERING INDEX Person_childId
SEARCH Child USING INDEX sqlite_autoindex_Child_1 (childId=?) LEFT-JOIN这看起来很棒对吧?但我很好奇这是否是“完整”计划。这是因为some_int 没有索引。但是查询计划并没有揭示这一点,我在任何地方都看不到过滤。数据库必须在此字段上筛选,对吗?
当我在单独的查询中执行some_int字段时,它显示了一个SCAN,就像我在上一个查询计划中看到的一样,因为没有索引。
explain query plan select * from Child where some_int = 0;给予:
SCAN Child现在我的问题是:
SCAN Child?SCAN在Person上而不是SEARCH上发布于 2022-10-03 08:47:38
你应该看看此页。它深入解释了sqlite查询计划器,您可以找到所有问题的答案。注意,像WHERE some_int=0这样的过滤条件不会显示在查询计划中,因为它们不会影响计划,而只会影响结果集。
简单地说:
为什么在第一个查询计划中没有显示“扫描子”?
因为,由于LEFT JOIN,sqlite需要SCAN Person,并且对于每一行人,使用ChildId上的索引在Child中找到相应的记录。
为什么要对人进行扫描而不是搜索?
SCAN意味着按表的存储顺序读取表的所有行。SEARCH是对表中单个值的查找,使用索引查找rowid,使用rowid查找表的该行,而无需扫描所有te表以找到该行。因为您的查询需要读取所有的Person.childId,所以它会进行完整的扫描。
第一个查询计划是“快速”还是仍然需要添加索引?
您的查询已经使用了它可以使用的所有索引,所以它已经尽可能快地得到它。
https://stackoverflow.com/questions/73910788
复制相似问题