如何减小iphone的sqlite3数据库的大小?

编辑:非常感谢所有的答案。 以下是目前应用优化后的结果:

  • 切换到排序字符和运行长度编码 – 新数据库大小42M
  • 删除布尔值上的索引 – 新数据库大小为33M

非常好的部分是这不需要在iphone代码中进行任何更改

我有一个iphone应用程序,其中包含一个以sqlite格式保存的大型字典(只读)。 我正在寻找减少DB文件大小的想法,目前这个文件非常大。

以下是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 

…每个条目平均大约135个字节。

这是我的数据库架构:

 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) 

以下是一些示例数据:

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

最后一个字段表示字谜检索的字母频率(每个位置在0..9范围内)。 两个布尔代表子词典。

我需要做以下的查询:

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

我的一个想法是更有效地编码字母频率,例如二进制编码为blob(可能有RLE,因为有很多零?)。 有关如何最好地实现这一点的想法,或其他减少尺寸的想法? 我正在用ruby构建数据库,并在目标C中通过电话阅读它。

还有什么方法可以获得数据库的统计数据,所以我可以看到什么使用最多的空间?

我不清楚签名字段的所有用例,但似乎存储字母的字母顺序版本将是有益的。

您是否尝试键入“vacuum”命令以确保在忘记重新捕获的数据库中没有额外空间?

删除sowpods和twl上的索引 – 它们可能无法帮助您查询时间并且肯定占用了大量空间。

您可以使用SQLite下载页面中的 sqlite3_analyzer获取数据库的统计信息。

作为一种完全不同的方法,您可以尝试使用bloomfilter而不是综合数据库。 基本上,布隆filter由一堆散列函数组成,每个散列函数都与一个位域相关联。 对于每个合法字,评估每个散列函数,并设置相应位字段中的相应位。 缺点是理论上可能会得到误报,但是这些可以通过足够的哈希来最小化/实际消除。 加上一方是节省了大量空间。

SQLite的创建者销售包含数据库压缩(和加密)的SQLite版本。 这将是完美的。

你最好的选择是使用压缩,遗憾的是SQLite此时并不支持。 幸运的是,有人花时间为它开发了一个压缩扩展 ,这可能是你需要的。

否则,我建议您以压缩格式存储数据,并在运行时解压缩。

作为文本字段, signature当前每个条目至少使用26 * 8字节(208字节),但如果要将数据打包到位域中,则每个字母只能使用3位(减少每个字母的最大频率)致7)。 这意味着您可以将整个签名打包成26 * 3位= 78位= 10个字节。 即使你每个字母使用4位(每个字母的最大频率为15),你也只能使用104位(13字节)。

编辑:经过一番思考后,我认为每个字母4位(而不是3位)会更好,因为它会使二进制数学更容易。

EDIT2:通过关于SQLite数据类型的文档阅读,似乎你可能只需要使“签名”字段跨越类似INTEGER的26列,而SQLite将做正确的事情,并且只使用所需的多个位来存储值。

我是否正确地估计您的数据库中有大约450K这样的单词?

我对iPhone没有任何线索,也没有认真对待sqlitem但是…只要sqlite不允许一种方法将文件立即保存为gz(它可能已经在内部?不,看起来不像那样你说它每个条目大约135 b。甚至没有两个索引),我会远离表格方法,在字典方法压缩中 “手动”保存,并在运行和内存中构建其余部分。 这应该对您的数据类型执行得非常好。

等等……您是否使用该签名来进行全文搜索或错误识别? 在sqlite上全文搜索不会废弃那个字段吗?

如上所述,更有效地存储“签名”似乎是一个好主意。

然而,似乎你可以通过使用某种单词的查找表来节省大量的空间 – 因为你似乎在接受一个词根,然后附加“er”,“ed”,“es”等等为什么没有一个带有数字ID的列,该列引用来自单独查找表的根词,然后是一个带有数字ID的单独列,该列引用将附加到基本单词的常用单词后缀表。

如果在存储具有单个根词的多个条目的签名的简写版本时存在任何技巧,您还可以使用这些来减少存储签名的大小(不确定哪些算法产生这些值)

这对我来说似乎也很有意义,因为你有“word”列作为主键,但是甚至没有索引它 – 只需创建一个单独的数字列,它是表的主要ID。

嗯…一部iPhone ……它没有永久数据连接吗? 我认为这是webapplication / webservice可以顺利进行的地方。 将您的大多数业务逻辑移至Web服务器(他将使用FTS和looooots内存获得真正的SQL)并在线获取该信息到设备上的客户端。

正如其他地方所提到的,丢失布尔列上的索引,它们几乎肯定会比表扫描更慢(如果使用的话)并且将不必要地使用空间。

我考虑对单词应用简单的压缩, 霍夫曼编码对于这类事情非常有用。 另外,我会看一下签名:按字母频率顺序对列进行排序,不要打扰存储尾随零,这可以暗示。 我想你也可以对霍夫曼进行编码。

当然,总是假设您的编码字符串不会扰乱SQLite。