使用覆盖索引

时间:2016-04-15 15:51:18

标签: optimization sqlite

在我们公司,我们有一个相当大的SQLite3数据库,比如说,有些兴趣点(POI)。数据库创建一次,并在移动用户应用程序中以只读模式使用。

POI的名称可以包含多个带变音符号的单词和字母。要在应用程序中快速搜索POI,还有一个附加表,其中包含单个大写ASCII字和主表中的相应ID。还有覆盖索引。数据库看起来像这样(简化):

CREATE TABLE poi(id INTEGER PRIMARY KEY, name TEXT, attributes TEXT);
CREATE TABLE poi_search (word TEXT, poi_id INTEGER);
CREATE INDEX poi_search_idx ON poi_search(word, poi_id);

然后,您可以使用以下请求查询名称中包含"FOO"的POI:

SELECT * from poi INNER JOIN poi_search ON poi.id=poi_search.poi_id 
   WHERE poi_search.word < 'FOO' AND poi_search.word < 'FOP';

查询非常快,并使用覆盖索引,因此根本不需要访问poi_search表:

sqlite> EXPLAIN QUERY PLAN SELECT * from poi INNER JOIN poi_search ON poi.id=poi_search.poi_id WHERE poi_search.word < 'FOO' AND poi_search.word < 'FOP';
0|0|1|SEARCH TABLE poi_search USING COVERING INDEX poi_search_idx (word<?)
0|1|0|SEARCH TABLE poi USING INTEGER PRIMARY KEY (rowid=?)

我刚刚意识到这是一个很大的浪费空间,因为覆盖索引会复制索引表的所有数据。在应用程序中,表poi_search实际上从不使用。

有一种方法,即使是一个棘手的方法,删除或截断poi_search表,同时保留覆盖索引中的所有数据?我知道这样的数据库将处于不连贯的状态,因此可能没有办法使用官方API进行这样的黑客攻击。

我不在乎有一个用于生成数据库的黑客版SQLite3;但是DB必须在vanilla SQLite3客户端中为给定的请求生成正确的搜索值。

1 个答案:

答案 0 :(得分:1)

做你想做的事并没有什么棘手的方法或者黑客。 您必须使用documented way,这可以保证数据库的一致性:

CREATE TABLE poi_search (
    word TEXT PRIMARY KEY,
    poi_id INTEGER
) WITHOUT ROWID;
-- no other index needed