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

时间:2008-12-30 20:50:57

标签: iphone ruby sqlite compression

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

  • 切换到排序字符和运行长度编码 - 新数据库大小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中通过电话阅读。

还有什么方法可以在数据库上获取统计数据,这样我就可以看到使用最多空间的内容了吗?

11 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:4)

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

您可以使用SQLite downloads page中的 sqlite3_analyzer 获取数据库的统计信息。

答案 2 :(得分:3)

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

答案 3 :(得分:2)

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

答案 4 :(得分:1)

你最好的选择是使用压缩,不幸的是,SQLite此时并不支持原生。幸运的是,有人花时间为它开发compression extension,这可能是你需要的。

否则我建议主要以压缩格式存储数据并动态解压缩。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

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

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

EDIT2:通过SQLite data types上的文档阅读,似乎你可以让“签名”字段跨越类似INTEGER的26列,SQLite将做正确的事情并且只使用尽可能多的位根据需要存储值。

答案 7 :(得分:0)

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

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

等等......您是否正在使用该签名来进行全文搜索或错误识别? sqlite上的full text search会不会废弃该字段吗?

答案 8 :(得分:0)

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

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

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

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

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

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