5

这与为什么 SQLite 拒绝使用可用索引有关?

创建数据库的查询是:

创建表 foo(id TEXT);
在 foo(id) 上创建索引 `foo.index`;
创建表栏(id TEXT);
在 bar(id) 上创建索引 `bar.index`;
CREATE VIEW baz AS SELECT id FROM foo UNION ALL SELECT id FROM bar;
CREATE TABLE bam(id TEXT, value TEXT);

插入 foo 值('123');
插入 foo 值('1123');
插入 foo 值('2123');
插入 foo 值('3123');

插入柱值('44123');
插入柱值('441123');
插入柱值('442123');
插入柱值('443123');

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

扫描表 foo(~1000000 行)
扫描表栏(~1000000 行)
复合子查询 2 和 3(联合所有)
扫描子查询 1(~2000000 行)
执行列表子查询 4
搜索表 bam 使用自动覆盖索引 (id=?) (~7 行)

编辑:有趣的是,如果我这样做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)

4

3 回答 3

5

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

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

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

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

于 2013-10-30T08:37:01.763 回答
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)
于 2013-11-07T19:08:30.873 回答
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');

祝你好运

于 2013-11-05T00:44:45.897 回答