Comment réduire la taille d'une base de données sqlite3 pour l'iphone?
edit: merci beaucoup pour toutes les réponses. Voici les résultats après l'application de la optimisations:
- De commutation pour trier les caractères et la longueur de codage - DB taille 42M
- La suppression des index sur les opérations booléennes - DB taille 33M
La très belle partie est, ce n'est pas nécessaire de toutes les modifications dans l'iphone code
J'ai une application iphone avec un gros dictionnaire tenue au format sqlite (lecture seule). Je suis à la recherche d'idées pour réduire la taille du fichier de base de données, qui est actuellement très grand.
Ici est le nombre d'entrées et la taille de la DB sqlite:
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
...une moyenne d'environ 135 octets par entrée.
Voici ma DB schéma:
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)
Voici quelques exemples de données:
photoengrave|1|1|10002011000001210101010000
photoengraved|1|1|10012011000001210101010000
photoengraver|1|1|10002011000001210201010000
photoengravers|1|1|10002011000001210211010000
photoengraves|1|1|10002011000001210111010000
photoengraving|1|1|10001021100002210101010000
Le dernier champ représente la lettre de fréquences pour l'anagramme de recherche (chaque position est dans la plage 0..9). Les deux booléens représenter sous les dictionnaires.
J'ai besoin de faire des requêtes telles que:
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')
Une idée que j'ai est de coder la lettre de fréquences de manière plus efficace, par exemple binaire coder comme un blob (peut-être avec RLE comme il y a beaucoup de zéros?). Toutes les idées sur la meilleure façon de réaliser cela, ou d'autres idées pour réduire la taille? Je suis la construction de la DB en ruby, et la lecture sur le téléphone en objective C.
Aussi est-il possible d'obtenir des statistiques sur la DB de sorte que je peux voir ce qui est à l'aide de la plupart de l'espace?
non, je n'ai pas, cependant, comme je n'ai jamais supprimé quoi que ce soit (ce qui est construit à partir de zéro en utilisant un script ruby) je ne pensais pas que c'était nécessaire.
afin de clarifier ce dernier commentaire, je viens d'importer à partir d'un fichier texte (au format de l'échantillon de données), en utilisant ceci: sqlite3 dictionnaire.db".l'importation dictionary.txt mots
À droite, il n'y a pas de fragmentation, ce qui signifie que le vide ne serait probablement pas vous être d'une quelconque aide.
Important mot d'avertissement pour les gens qui lisent ceci: si vous utilisez implicite rowids sur votre sqlite3 tables, VIDE peut (et va!) supprimer certains de vos lignes.
OriginalL'auteur frankodwyer | 2008-12-30
Vous devez vous connecter pour publier un commentaire.
Je ne suis pas clair sur tous les cas d'utilisation pour le champ de signature, mais il semble que le stockage en ordre alphabétique) une version de la parole au lieu de cela serait bénéfique.
Bonne idée! La seule amélioration que je pense de cette méthode serait de remplacer des séquences de 3 lettres ou plus dans une ligne avec un numéro et la lettre. Par exemple, si votre signature pour "mississippi" est "iiiimppssss" on pourrait raccourcir en "4impp4s"
aussi une belle idée...en plus il fonctionnera probablement sans changer mon actuel iphone code (encore serait-il suffit de regarder pour l'égalité). Je vais essayer ça aussi. des points supplémentaires pour les portions de code qui calcule la signature étant donné un mot 🙂
S'il vous plaît excuser la crudity de cette solution que je ne sais pas vraiment Ruby: "mississippi".split( // ).de tri.rejoignez.gsub(/(.)\1{2,}/) { |s| s.longueur.to_s + s[0,1] }
J'ai mis en place une autre question à explorer cette option un peu plus. stackoverflow.com/questions/401834/...
OriginalL'auteur Robert Simmons
Avez-vous essayé de taper "vide" de commande pour vous assurer de ne pas avoir de l'espace supplémentaire dans la base de données que vous avez oublié de reclame?
Important mot d'avertissement pour les gens qui lisent ceci: si vous utilisez implicite rowids sur votre sqlite3 tables, VIDE peut (et va!) supprimer certains de vos lignes.
OriginalL'auteur Jared
Supprimer l'index sur popotamo et twl-ils sont probablement pas aider votre requête et sont certainement prendre beaucoup d'espace.
Vous pouvez obtenir des statistiques sur la base de données à l'aide de sqlite3_analyzer de la SQLite page des téléchargements.
OriginalL'auteur Doug Currie
Comme une approche totalement différente, vous pouvez essayer d'utiliser un filtre de bloom au lieu d'une base de données complète. Fondamentalement, une floraison de filtre se compose d'une série de fonctions de hachage, dont chacun est associé à un champ de bits. Pour chaque mot, chaque fonction de hachage est évaluée, et le bit correspondant dans le champ de bits est définie. Inconvénient c'est que c'est théoriquement possible d'obtenir des faux positifs, mais ceux-ci peuvent être minimisés/a pratiquement éliminé avec suffisamment de tables de hachage. Côté positif est un énorme gain de place.
OriginalL'auteur recursive
Le créateur de SQLite vend une version de SQLite qui comprend base de données de compression et de cryptage). Ce serait parfait.
OriginalL'auteur dicroce
Votre meilleur pari est d'utiliser la compression, qui, malheureusement, SQLite ne supporte pas nativement à ce point. Heureusement, quelqu'un a pris le temps de développer une extension de compression pour ce qui pourrait être ce dont vous avez besoin.
Sinon je vous recommande le stockage de vos données principalement dans le format de compression et de décompression à la volée.
En fait, cette extension appeler tous être fait avec ce que l'API SQLite en utilisant de simples SQLite Udf.
OriginalL'auteur Eran Galperin
Comme un champ de texte,
signature
est actuellement à l'aide d'au moins 26 * 8 octets par entrée (208 octets) mais si vous pack les données dans un champ de bits, vous pouvez probablement vous en sortir avec seulement 3 bits par lettre (réduction de votre fréquence maximale par lettre à 7). Ce qui signifierait que vous pourriez emballer l'ensemble de la signature en 26 * 3 bits = 78 bits = 10 octets. Même si vous avez utilisé 4 bits par lettre (pour une fréquence maximale de 15 par lettre) vous devez utiliser uniquement de 104 bits (octets 13).EDIT: Après un peu plus de réflexion, je pense que 4 bits par lettre (au lieu de 3) serait une meilleure idée parce que ce serait rendre les mathématiques binaires plus facile.
EDIT2: la Lecture à travers les docs sur Types de données SQLite, il semble que vous pourriez être en mesure de faire juste le champ "signature" durée de 26 colonnes de type ENTIER et SQLite va faire la bonne chose et uniquement utiliser un nombre de bits nécessaire pour stocker la valeur.
Aussi, en arrondissant les octets 13 à 16 ans, ce peut même être divisée en deux 8 octets entiers, qui SQLite prend en charge, permettant l'utilisation d'index sur les tables. Cette approche exige que la signature soit divisé en deux, et la requête aurait besoin de vérifier l'égalité sur les deux.
Oui je pensais à quelque chose le long de ces lignes...chaque position dans le champ de signature est 0..9 pourrait être emballés en 4 bits. Le codage de la signature d'un grand entier binaire je pense que ce serait encore plus petit.
voulez-vous dire que je ne peut pas indexer les gouttes?
frankodwyer, je ne suis pas sûr à propos de l'indexation des gouttes.
OriginalL'auteur Marc Novakowski
Faire je pense bien que vous avez au sujet de 450K ce genre de mots dans votre base de données ?
J'ai aucune idée sur l'iPhone, ni sérieux au sujet de sqlitem mais... tant que sqlite ne permettent pas un moyen d'enregistrer le fichier en tant que gz tout de suite (peut-être déjà fait à l'interne? non, ne regardez pas comme ça, quand vous dites que c'est environ 135 b par entrée. pas de même avec les deux index), je l'éloigner de l'approche de table, le sauver "manuellement" dans un dictionnaire approche de compression et de construire le reste à la volée et dans la mémoire. Que doit effectuer TRÈS bien sur votre type de données.
Attendre... Êtes-vous à l'aide de cette signature pour permettre fulltextsearching ou erreur de frappe recogition ? Serait recherche en texte intégral sur sqlite pas obsolète ce domaine ?
OriginalL'auteur lImbus
Comme l'a noté le stockage de "Signature" de manière plus efficace semble être une bonne idée.
Cependant, il semble aussi que vous pourriez obtenir une tonne de réduction de l'espace en utilisant une sorte de table de recherche pour les mots - puisque vous semblez prendre un mot-racine et en ajoutant "er", "ed", "es", etc, pourquoi ne pas avoir une colonne avec un IDENTIFIANT numérique qui fait référence à un mot-racine à partir d'une autre table de recherche, puis une colonne séparée avec un IDENTIFIANT numérique qui fait référence à une table de la parole commune suffixes qui sera annexé à la base de word.
S'il y avait des trucs autour de stocker des versions abrégées des signatures pour des entrées multiples avec une seule racine du mot, vous pourriez également employer ceux de réduire la taille des signatures stockées (pas sûr de ce que l'algorithme est la production de ces valeurs)
Cela semble également faire beaucoup de sens pour moi que vous avez la "parole" de la colonne comme clé primaire, mais ne même pas l'indice de la peine de créer une colonne numérique, qui est le principal de l'ID de la table.
re la clé primaire, je comprends, il est automatiquement indexé dans sqlite
OriginalL'auteur Kendall Helmstetter Gelner
mhmm... un iPhone... il n'a pas de permanent des données de connexion ?
Je pense que c'est là une webapplication/webservice peut sauter dans confortablement.
Passer la plupart de votre logique métier sur le serveur (il va avoir de vraies SQL avec FTS et looooots de mémoire) et de chercher de l'info en ligne pour le client sur l'appareil.
OriginalL'auteur lImbus
Comme mentionné ailleurs, de perdre de l'index sur les colonnes booléennes, ils vont presque certainement être plus lent (si utilisée) qu'une analyse de table et va utiliser inutilement de l'espace.
J'avais envisager d'appliquer une compression simple pour les mots, Le codage de Huffman est assez bon pour ce genre de chose. Aussi, je regarderais les signatures de: trier les colonnes dans la lettre de fréquence de l'ordre et de ne pas la peine de stocker des zéros à la fin, ce qui peut être implicite. Je suppose que vous pourriez Huffman-encoder ceux, trop.
Toujours en supposant que votre encodées n'est pas en colère SQLite, bien sûr.
OriginalL'auteur Mike Woodhouse