7 Stimmen

Wie kann man die Größe einer sqlite3-Datenbank für das iPhone verringern?

edit: Vielen Dank für die vielen Antworten. Hier sind die Ergebnisse nach der Anwendung der Optimierungen so weit:

  • Umstellung auf Sortierung der Zeichen und Lauflängenkodierung - neue DB-Größe 42M
  • Weglassen der Indizes für die Booleschen Werte - neue DB-Größe 33M

Das Schöne daran ist, dass dafür keine Änderungen am iPhone-Code erforderlich sind.

Ich habe eine iPhone-Anwendung mit einem großen Wörterbuch im Sqlite-Format (nur Lesen). Ich bin auf der Suche nach Ideen, um die Größe der DB-Datei zu reduzieren, die derzeit sehr groß ist.

Hier ist die Anzahl der Einträge und die daraus resultierende Größe der sqlite DB:

franks-macbook:DictionaryMaker frank$ ls -lh dictionary.db
-rw-r--r--  1 frank  staff    59M  8 Oct 23:08 dictionary.db
franks-macbook:DictionaryMaker frank$ wc -l dictionary.txt
  453154 dictionary.txt

...durchschnittlich etwa 135 Bytes pro Eintrag.

Hier ist mein DB-Schema:

create table words (word text primary key, sowpods boolean, twl boolean, signature text)
create index sowpods_idx on words(sowpods)
create index twl_idx on words(twl)
create index signature_idx on words(signature)

Hier sind einige Beispieldaten:

photoengrave|1|1|10002011000001210101010000
photoengraved|1|1|10012011000001210101010000
photoengraver|1|1|10002011000001210201010000
photoengravers|1|1|10002011000001210211010000
photoengraves|1|1|10002011000001210111010000
photoengraving|1|1|10001021100002210101010000

Das letzte Feld stellt die Buchstabenhäufigkeiten für die Anagrammsuche dar (jede Position liegt im Bereich 0..9). Die beiden Booleschen Werte stehen für Unterwörterbücher.

Ich muss Abfragen wie diese durchführen:

select signature from words where word = 'foo'
select word from words where signature = '10001021100002210101010000' order by word asc
select word from words where word like 'foo' order by word asc
select word from words where word = 'foo' and (sowpods='1' or twl='1')

Eine Idee, die ich habe, ist, die Buchstabenfrequenzen effizienter zu kodieren, z. B. binär als Blob (vielleicht mit RLE, da es viele Nullen gibt?) zu kodieren. Irgendwelche Ideen, wie man das am besten erreicht, oder andere Ideen, um die Größe zu reduzieren? Ich erstelle die DB in Ruby und lese sie auf dem Telefon in Objective C.

Gibt es auch eine Möglichkeit, Statistiken über die DB zu erhalten, damit ich sehen kann, was den meisten Platz verbraucht?

1voto

dicroce Punkte 43066

Der Schöpfer von SQLite verkauft eine Version von SQLite, die Datenbankkomprimierung (und -verschlüsselung) enthält. Das wäre perfekt.

1voto

Marc Novakowski Punkte 43303

Als Textfeld, signature benötigt derzeit mindestens 26 * 8 Bytes pro Eintrag (208 Bytes), aber wenn Sie die Daten in ein Bitfeld packen würden, könnten Sie wahrscheinlich mit nur 3 Bits pro Buchstabe auskommen (was die maximale Häufigkeit pro Buchstabe auf 7 reduziert). Das würde bedeuten, dass Sie die gesamte Unterschrift in 26 * 3 Bits = 78 Bits = 10 Bytes packen könnten. Selbst wenn Sie 4 Bits pro Buchstabe verwenden würden (bei einer maximalen Häufigkeit von 15 pro Buchstabe), würden Sie nur 104 Bits (13 Bytes) benötigen.

EDIT: Nach längerem Nachdenken denke ich, dass 4 Bits pro Buchstabe (statt 3) eine bessere Idee wären, weil es die binäre Mathematik einfacher machen würde.

EDIT2: Ich habe mir die Dokumente über SQLite-Datentypen Es scheint, dass Sie das Feld "Signatur" einfach auf 26 Spalten vom Typ INTEGER aufteilen können und SQLite wird das Richtige tun und nur so viele Bits wie nötig verwenden, um den Wert zu speichern.

0voto

lImbus Punkte 1567

Gehe ich recht in der Annahme, dass Sie etwa 450.000 solcher Wörter in Ihrer Datenbank haben?

Ich habe keine Ahnung von iPhone, weder ernsthaft über sqlitem aber... solange sqlite nicht für einen Weg, um die Datei als gz sofort zu speichern (es vielleicht bereits intern? nein, sieht nicht so aus, wenn Sie sagen, es ist etwa 135 b pro Eintrag. nicht einmal mit beiden Indizes), würde ich weg von der Tabelle Ansatz, speichern Sie es "manuell" in einem wörterbuchbasierte Komprimierung und erstellen den Rest spontan und im Speicher. Das sollte SEHR gut auf Ihre Art von Daten durchführen.

Warten Sie... Verwenden Sie diese Signatur, um eine Volltextsuche oder eine Erkennung von Tippfehlern zu ermöglichen? Würde Volltextsuche auf Sqlite dieses Feld nicht veraltet?

0voto

Wie bereits erwähnt, scheint eine effizientere Speicherung der "Unterschrift" eine gute Idee zu sein.

Allerdings scheint es auch, wie Sie eine Tonne Platz sparen könnten, indem Sie eine Art von Lookup-Tabelle für Wörter - da Sie scheinen zu sein, die ein Root-Wort und dann anhängen "er", "ed", "es", etc warum nicht eine Spalte mit einer numerischen ID, die ein Root-Wort aus einer separaten Lookup-Tabelle verweist, und dann eine separate Spalte mit einer numerischen ID, die eine Tabelle der gemeinsamen Wort-Suffixe, die an das Basiswort angehängt werden würde verweist.

Wenn es irgendwelche Tricks gäbe, um Kurzversionen von Signaturen für mehrere Einträge mit einem einzigen Root-Wort zu speichern, könnten Sie diese auch verwenden, um die Größe der gespeicherten Signaturen zu verringern (ich bin nicht sicher, welcher Algorithmus diese Werte erzeugt)

Dies scheint mir auch sehr sinnvoll zu sein, da Sie die Spalte "Wort" als Primärschlüssel haben, sie aber nicht einmal indizieren, sondern nur eine separate numerische Spalte erstellen, die die Primär-ID für die Tabelle ist.

0voto

lImbus Punkte 1567

Mhmm... ein iPhone... hat es nicht eine permanente Datenverbindung? Ich denke, hier kann eine Webanwendung/Webservice sehr gut einspringen. Verschieben Sie den größten Teil Ihrer Geschäftslogik auf den Webserver (er wird echtes SQL mit FTS und sehr viel Speicher haben) und holen Sie diese Informationen online auf den Client auf dem Gerät.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X