请考虑以下示例:
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b) WITHOUT ROWID;
WITH RECURSIVE
cnt(x) AS (VALUES(1000) UNION ALL SELECT x+1 FROM cnt WHERE x<2000)
INSERT INTO t1(a,b) SELECT x, x FROM cnt;
CREATE INDEX t1b ON t1(b);
此查询创建没有rowid列的表,并插入值(x,x) 1000&lt; x&lt; 2000.为了帮助查询计划程序,让我们运行ANALYZE。
ANALYZE;
EXPLAIN QUERY PLAN
SELECT * FROM t1 WHERE b BETWEEN 500 AND 2500;
EXPLAIN QUERY PLAN
SELECT * FROM t1 WHERE b BETWEEN 2900 AND 3000;
两种情况下的输出是:0|0|0|SEARCH TABLE t1 USING COVERING INDEX t1b (b>? AND b<?)
但是,使用索引(对于第一个查询)没有任何意义,因为无论如何我们必须遍历整个表,因此普通的SCAN TABLE似乎更有效。正是以这种方式表格与rowid工作:
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a, b);
WITH RECURSIVE
cnt(x) AS (VALUES(1000) UNION ALL SELECT x+1 FROM cnt WHERE x<2000)
INSERT INTO t1(a,b) SELECT x, x FROM cnt;
CREATE INDEX t1a ON t1(a);
ANALYZE;
EXPLAIN QUERY PLAN
SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500;
EXPLAIN QUERY PLAN
SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000;
在这种情况下,输出将是:0|0|0|SCAN TABLE t1
和0|0|0|SEARCH TABLE t1 USING INDEX t1a (a>? AND a<?)
那么,是否可以解释查询规划器如何优化WITHOUT ROWID表的查询?
答案 0 :(得分:2)
两种情况下的输出是: 0 | 0 | 0 |搜索表t1使用覆盖索引t1b(b&gt;?和b <?)
然而,没有意义使用索引(for 第一个查询)因为无论如何我们必须迭代 整个表,所以普通的SCAN TABLE似乎更有效率。
您错过了 COVERING INDEX 部分:这意味着它正在使用仅索引 - 根本不访问该表。
如果需要所有行,则正确的索引访问(没有“COVERING”)可能比全表扫描慢,但对于仅索引扫描则不是这样。
在此处阅读有关仅索引扫描的详情:http://use-the-index-luke.com/sql/clustering/index-only-scan-covering-index
修改强>
WITHOUT ROWID在SQLite中的是其他数据库中所谓的聚簇索引:它们包含所有表列。因此,即使您选择了所有列(例如select *
),也无需访问该表。
在此处阅读有关聚簇索引的更多信息:http://use-the-index-luke.com/sql/clustering/index-organized-clustered-index