Pergunta

edit: muito obrigado por todas as respostas. Aqui estão os resultados após a aplicação das otimizações até agora:

  • Mudar para classificar a personagens e codificação run-length - nova 42M tamanho DB
  • Soltando os índices nas booleans - novo tamanho DB 33M

A parte realmente interessante é que não exigiu nenhuma alteração no código iphone

Eu tenho um aplicativo para iPhone com um grande dicionário realizada em formato sqlite (somente leitura). Estou à procura de ideias para reduzir o tamanho do arquivo DB, que atualmente é muito grande.

Aqui está o número de entradas e tamanho resultante do 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

... uma média de cerca de 135 bytes por entrada.

Aqui está o meu esquema DB:

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)

Aqui está alguns dados de exemplo:

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

O último campo representa a letra frequências para recuperação de anagrama (cada posição está na faixa 0..9). Os dois booleans representam sub dicionários.

Eu preciso fazer consultas, tais como:

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

Uma ideia que eu tenho é para codificar a letra freqüências de forma mais eficiente, por exemplo, codificação binária-los como um blob (talvez com RLE, pois há muitos zeros?). Alguma idéia para a melhor forma de alcançar este objectivo, ou outras ideias para reduzir o tamanho? Estou construindo o DB em Ruby, e lê-lo ao telefone em C. objetivo

Além disso, há alguma maneira de obter estatísticas sobre o DB para que eu possa ver o que está usando mais espaço?

Foi útil?

Solução

Eu não estou claro sobre todos os casos de uso para o campo de assinatura, mas parece que armazenar uma versão em ordem alfabética da palavra em vez seria benéfica.

Outras dicas

Você tentou digitar o comando "vácuo" para se certificar de que você não tem espaço extra no db você se esqueceu de reclame?

Remova os índices em SOWPODS e TWL -. Eles provavelmente não estão ajudando seus tempos de consulta e são definitivamente tomar muito espaço

Você pode obter estatísticas sobre o banco de dados usando sqlite3_analyzer página na SQLite de downloads .

O criador do SQLite vende uma versão do SQLite que inclui compressão de banco de dados (e criptografia). Isso seria perfeito.

Sua melhor aposta é a de compressão de uso, o que, infelizmente, SQLite não suporta nativamente neste momento. Felizmente, alguém tomou o tempo para desenvolver um compressão extensão para ele que poderia ser o que você precisa.

Caso contrário, eu recomendo armazenar seus dados na sua maioria em formato comprimido e descompactar na mosca.

Como um campo de texto, signature está usando atualmente pelo menos 26 * 8 bytes por entrada (208 bytes), mas se você fosse para embalar os dados em um campo de bits, você poderia provavelmente começar afastado com apenas 3 bits por carta (reduzindo o seu frequência máxima para cada carta de 7). Isso significaria que você poderia embalar toda a assinatura em 26 * 3 bits = 78 bits de = 10 bytes. Mesmo se você usou 4 bits por carta (para uma frequência máxima de 15 por carta) só iria usar 104 bits (13 bytes).

EDIT:. Depois de um pouco mais pensamento, acho que 4 bits por carta (em vez de 3) seria uma idéia melhor porque faria o binário matemática mais fácil

EDIT2: Leitura através dos docs sobre SQLite tipos de dados , parece que você pode ser capaz de fazer apenas a "assinatura" span campo 26 colunas do tipo inteiro e SQLite vai fazer a coisa certa e só usar tantos bits como necessário para armazenar o valor.

Eu acho corretamente que você tem cerca de 450k palavras como que em seu banco de dados?

Eu não tenho nenhum indício sobre iPhone, nem sério sobre sqlitem mas ... enquanto sqlite não permite uma maneira de salvar o arquivo como gz imediatamente (ele talvez já faz internamente? Não, não parece assim quando você diz que é cerca de 135 b por entrada. nem mesmo com ambos os índices), eu iria afastar-se da abordagem de mesa, salvá-lo "manualmente" em um dicionário compressão abordagem e construir o resto na mosca e na memória. Isso deve funcionar muito bem no seu tipo de dados.

Wait ... Você está usando essa assinatura para permitir fulltextsearching ou erros de digitação recogition? Seria pesquisa de texto completo em sqlite não obsoleta nesse campo?

Como observado o armazenamento de "assinatura" de forma mais eficiente parece ser uma boa ideia.

No entanto, também parece que você poderia ganhar uma tonelada de economia de espaço, usando algum tipo de tabela de pesquisa por palavras - desde que você parece estar levando uma palavra de raiz e, em seguida, acrescentando "er", "ed", "es" , etc, porque não têm uma coluna com uma identificação numérica que referências uma palavra de raiz a partir de uma tabela de pesquisa em separado, e em seguida uma coluna separada com uma identificação numérica que faz referência a uma tabela de sufixos de palavras comuns que iria ser anexado à palavra de base.

Se não houvesse nenhum truques em torno de armazenar versões taquigráficas de assinaturas para várias entradas com uma única palavra de raiz, você também poderia empregar os para reduzir o tamanho das assinaturas armazenados (não sei o algoritmo está produzindo esses valores)

Isso também parece fazer muito sentido para mim como você tem a coluna "palavra" como uma chave primária, mas nem sequer indexá-lo -. Apenas criar uma coluna numérico separado que é o ID primária para a tabela

mhmm ... um iPhone ... não é que tem uma conexão de dados permanente? Acho que este é o lugar onde um webapplication / webservice pode saltar em confortavelmente. Mova a maioria de sua lógica de negócios para o servidor web (que ele vai ter o SQL real com STF e looooots de memória) e buscar essa informação on-line para o cliente no dispositivo.

Como mencionado em outros lugares, perdem os índices nas colunas boolean, eles quase certamente será mais lento (se usado em tudo) do que uma varredura da tabela e estão indo para usar o espaço desnecessariamente.

Eu considerar a aplicação de uma compressão simples para as palavras, Huffman é muito bom para este tipo de coisa. Além disso, eu olhar para as assinaturas: classificar as colunas em ordem carta frequência e não se incomodam armazenar zeros à direita, que podem ser implícitas. Acho que você poderia Huffman-codificar esses, também.

Sempre assumindo suas cordas codificados não perturbar SQLite, é claro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top