2016-04-15 6 views
0

In unserer Firma haben wir eine ziemlich große SQLite3-Datenbank mit, sagen wir, einige interessante Punkte (POI). Die Datenbank wird einmal erstellt und in einer mobilen Benutzeranwendung im schreibgeschützten Modus verwendet.Vermeiden Sie doppelte Daten in SQLite3 mit einem Deckungsindex

POI haben Namen, die mehrere Wörter und Buchstaben mit diakritischen Zeichen enthalten können. Um eine schnelle POI-Suche in der Anwendung durchzuführen, gibt es eine zusätzliche Tabelle mit einzelnen ASCII-Großbuchstaben und der entsprechenden ID in der Haupttabelle. Und es gibt eine Abdeckung Index. Die Datenbank sieht wie folgt aus (vereinfacht):

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

Dann Sie für POI-Namen enthalten, deren abfragen können "FOO" mit einer Anfrage wie folgt aus:

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

Die Abfrage ist sehr schnell und verwendet eine Abdeckung Index, es braucht also nicht auf alle poi_search Tabelle zuzugreifen:

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=?) 

ich nur realisiert Das ist eine große Verschwendung von Speicherplatz, da der Deckungsindex alle Daten der Indextabelle dupliziert. In der Anwendung wird die Tabelle poi_search tatsächlich nie verwendet.

In einem Weg, auch eine knifflige, um die poi_search Tabelle zu entfernen oder zu kürzen, während alle Daten im Deckungsindex zu halten? Ich weiß, dass solch eine Datenbank in einem inkohärenten Zustand sein wird, also gibt es wahrscheinlich keine Möglichkeit mit der offiziellen API einen solchen Hack zu machen.

Es ist mir egal, eine gehackte Version von SQLite3 für die Produktion der Datenbank zu haben; aber die Datenbank muss korrekte Suchwerte für die gegebene Anfrage in einem normalen SQLite3-Client erzeugen.

+1

„word [GLOB] (http://www.sqlite.org/lang_expr.html#like) ' FOO * '"wäre einfacher als zwei Vergleiche. –

Antwort

1

Es gibt keinen kniffligen Weg oder einen Hack, um zu tun, was Sie wollen. Sie werden mit dem documented way auskommen müssen, die die Datenbank konsistent zu halten ist garantiert:

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

Danke. Ich wusste nicht, dass SQLite3 eine Unterstützung für Tabellen ohne Rowid hatte und eine Textspalte als Primärindex unterstützt. – prapin

Verwandte Themen