这与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小提琴:http://sqlfiddle.com/#!7/32af2/14(使用WebSQL)
答案 0 :(得分:4)
不使用索引,因为不需要它们;他们不会加快查询速度。
在SQLite中,连接被实现为嵌套循环连接,也就是说,数据库遍历一个表的所有记录,并且对于每个记录,查找另一个表中的匹配记录。 只有第二个表中的查找才需要索引;只是浏览第一个表的所有记录不需要索引。
使用内部联接,查询优化器可以选择循环中的外部表或内部表(如果只有一个表具有索引,则应该是内部表)。 但是,使用左外连接时,没有选择,左表必须是外表。
要优化左外连接,(仅)右侧的表需要索引。
答案 1 :(得分:4)
查询规划器确定在这种情况下使用索引不再有效。但是,仍然可以通过以下方式修改视图来强制使用索引:
CREATE VIEW baz AS SELECT id FROM foo UNION ALL SELECT id FROM bar ORDER BY id;
ORDER BY
语句将在访问索引字段时强制使用索引。
新查询计划的结果:
EXPLAIN QUERY PLAN SELECT * FROM baz LEFT JOIN bam ON baz.id=bam.id WHERE baz.id IN ('123', '234');
SCAN TABLE foo USING COVERING INDEX foo.index (~4 rows)
SCAN TABLE bar USING COVERING INDEX bar.index (~4 rows)
COMPOUND SUBQUERIES 2 AND 3 (UNION ALL)
SCAN SUBQUERY 1 (~2 rows)
EXECUTE LIST SUBQUERY 4
SEARCH TABLE bam USING INDEX bam.index (id=?) (~1 rows)
答案 2 :(得分:0)
Union All非常难以优化,因为dbms将生成结果的临时副本。你必须专门找到关于如何实现union all的文档,但你可以在foobar列中进行设计。
CREATE TABLE Danny117(id TEXT, mytype TEXT);
INSERT INTO Danny117 VALUES('123', 'foo');
INSERT INTO Danny117 VALUES('1123', 'foo');
INSERT INTO Danny117 VALUES('2123', 'foo');
INSERT INTO Danny117 VALUES('3123', 'foo');
INSERT INTO Danny117 VALUES('44123','bar');
INSERT INTO Danny117 VALUES('441123','bar');
INSERT INTO Danny117 VALUES('442123','bar');
INSERT INTO Danny117 VALUES('443123','bar');
的结果
EXPLAIN QUERY PLAN SELECT Danny117.id, bam.* FROM Danny117 LEFT JOIN bam ON danny117.id=bam.id WHERE danny117.id IN ('123', '234');
祝你好运