2016-04-15 107 views
0

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

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); 

然后,您可以查询POI有了这样的请求,其名称包含"FOO"

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的黑客版本的数据库的生产;但数据库必须在香草SQLite3客户端中为给定请求生成正确的搜索值。

+1

“字[GLOB(http://www.sqlite.org/lang_expr.html#like)' “FOO *'”比两个比较简单。 –

回答

1

有没有棘手的方式,或黑客做你想做的。 你必须凑合着documented way,这是保证让数据库保持一致:

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

谢谢。我不知道SQLite3支持没有rowid的表,支持将文本列作为主索引。 – prapin