在我们公司,我们有一个相当大的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客户端中为给定的请求生成正确的搜索值。
答案 0 :(得分:1)
做你想做的事并没有什么棘手的方法或者黑客。 您必须使用documented way,这可以保证数据库的一致性:
CREATE TABLE poi_search (
word TEXT PRIMARY KEY,
poi_id INTEGER
) WITHOUT ROWID;
-- no other index needed