SQLite Explain Query Plan未显示完整步骤的三类技术疑问
SQLite左外连接查询计划疑问解答
1. 为何第一个执行计划未显示SCAN Child?
单独查询SELECT * FROM Child WHERE some_int = 0时的全表扫描,是因为没有索引能直接定位some_int=0的行,只能遍历整张表。但在左外连接的查询中,SQLite的执行逻辑是:
- 先通过Person的覆盖索引获取每条记录的
childId - 对非NULL的
childId,用Child的主键索引(sqlite_autoindex_Child_1)精准定位到对应行 - 最后对找到的Child行做
some_int=0的行级过滤
这个过滤是在精准定位单条行之后的字段检查,不属于全表扫描(SCAN)范畴,因此执行计划不会单独列出SCAN Child步骤。
2. 为何对Person表是SCAN而非SEARCH?
你的查询条件Person.childId IS NULL OR Child.some_int = 0无法转换为Person表索引可直接用于精准搜索的规则:
Person.childId IS NULL需要找出所有childId为空的Person记录,无法通过索引做范围或精准匹配,只能遍历索引条目Child.some_int=0是关联表的条件,无法映射到Person表的索引上做前置筛选
而Person_childId是覆盖索引(包含查询所需的childId字段,无需回表读取Person的其他字段),因此SQLite选择全量扫描该覆盖索引的所有条目,而非执行SEARCH。
3. 该执行计划是否高效,是否需要添加索引?
效率取决于数据规模和分布:
- 若两张表数据量都很小,当前计划性能完全够用,无需额外索引
- 若数据量较大,建议给Child表创建联合索引
(childId, some_int):
该索引能让SQLite通过childId查找Child行时,直接在索引内完成some_int=0的判断,无需回表读取Child完整行,减少IO开销 - 若Person表极大且
childId IS NULL的记录占比极低,可拆分查询:分别统计Person.childId IS NULL的数量,以及Person JOIN Child ON Person.childId=Child.childId WHERE Child.some_int=0的数量,再将结果相加。这种方式可利用索引分别优化两个子查询的效率
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

