sql - 为什么 SQLite 在添加 JOIN 时拒绝使用可用索引?

标签 sql sqlite query-optimization

这与 Why is SQLite refusing to use available indexes? 有关

创建数据库的查询是:

CREATE TABLE foo(id TEXT);
CREATE INDEX `foo.index` ON foo(id);
CREATE TABLE bar(id TEXT);
CREATE INDEX `bar.index` ON bar(id);
CREATE VIEW baz AS SELECT id FROM foo UNION ALL SELECT id FROM bar;
CREATE TABLE bam(id TEXT, value TEXT);

INSERT INTO foo VALUES('123');
INSERT INTO foo VALUES('1123');
INSERT INTO foo VALUES('2123');
INSERT INTO foo VALUES('3123');

INSERT INTO bar VALUES('44123');
INSERT INTO bar VALUES('441123');
INSERT INTO bar VALUES('442123');
INSERT INTO bar VALUES('443123');

EXPLAIN QUERY PLAN SELECT * FROM baz LEFT JOIN bam ON baz.id=bam.id WHERE baz.id IN ('123', '234'); 的结果是:

SCAN TABLE foo (~1000000 rows)
SCAN TABLE bar (~1000000 rows)
COMPOUND SUBQUERIES 2 AND 3 (UNION ALL)
SCAN SUBQUERY 1 (~2000000 rows)
EXECUTE LIST SUBQUERY 4
SEARCH TABLE bam USING AUTOMATIC COVERING INDEX (id=?) (~7 rows)

编辑:有趣的是,如果我这样做了 EXPLAIN QUERY PLAN SELECT * FROM (SELECT * FROM baz WHERE baz.id IN ('123', '234')) AS t LEFT JOIN bam ON t.id=bam.id ;它仍然不使用索引,但如果我使用 EXPLAIN QUERY PLAN SELECT * FROM baz WHERE baz.id IN ('123', '234');确实如此。这是怎么回事?

为什么不使用 foo 和 bar 上的索引??它确实使用了没有 JOIN 部分的索引,如链接问题中所示。

SQL fiddle :http://sqlfiddle.com/#!7/32af2/14 (使用 WebSQL)

最佳答案

没有使用索引,因为不需要;他们不会加快查询速度。

在SQLite中,join被实现为嵌套循环join,即数据库遍历一个表的所有记录,并针对每条记录在另一个表中查找匹配的记录。 只有第二个表中的查找需要索引;只遍历第一个表的所有记录不需要索引。

使用内连接,查询优化器可以在循环中选择哪个表是外表或内表(如果只有一个表有索引,它应该是内表)。 但是,对于左外连接,别无选择,左表必须是外表。

要优化左外连接,(仅)右侧的表需要索引。

关于sql - 为什么 SQLite 在添加 JOIN 时拒绝使用可用索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19671738/

相关文章:

sql - 我如何获得SQL中多列总和的最大值?

mysql - 选择大小写不工作 #1064

sqlite - 在 SQLite 中永久保存表

sqlite 引用的列名称仍然不区分大小写(功能或错误)

MySQL 合并索引优化不起作用

sql - 检查 SQL Server 2005 中的 KEYLOCK

mysql - 包含万亿记录的数据库表的查询计划

android - 在 Android 中 moveToNext() 失败之前对 getType() 和 getColumnNames() 的 SQL 调用?

MySQL 选择另一个表上的计数查询

sql - MySQL MyISAM 表性能问题重温