为什么SQLite拒绝使用可用的索引?

时间:2013-10-18 16:40:39

标签: sql sqlite

以下是在SQLite中创建两个表和一个视图的代码:

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 SELECT id FROM bar;

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 WHERE id='123';的结果是:

SCAN TABLE foo (~1000000 rows)
SCAN TABLE bar (~1000000 rows)
COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)
SCAN SUBQUERY 1 (~200000 rows)

SQL小提琴:http://sqlfiddle.com/#!7/b5e79/1(使用WebSQL)

正如您所看到的,当存在完全可用的索引时,它正在进行表扫描。为什么?如何修复此问题以使用索引?

1 个答案:

答案 0 :(得分:2)

这里可能会发生两件事

  • 表太小了。只需几行,所有数据都适合无论如何都要读取的块。因此优化器认为使用索引没有任何优势。这不太可能,因为所需的所有列都在索引中,因此需要更少的字节来填充。

  • 两个union之间的selects等于union distinct意味着消除了第一个和第二个选择中重复的所有行。要查找它们,数据库必须对两个结果集进行排序和合并。如果您需要union all这个排序步骤不是所有行,那么填充where子句的行将被放入结果集中。

试试union all。这应该使用索引。