7

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

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

真正好的部分是这不需要对 iphone 代码进行任何更改

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

这是 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 中通过电话阅读它。

还有什么方法可以获取数据库的统计信息,这样我就可以看到什么是使用最多的空间?

4

11 回答 11

5

您是否尝试过键入“vacuum”命令以确保您忘记回收的数据库中没有多余的空间?

于 2008-12-30T21:10:29.500 回答
4

删除 sowpods 和 twl 上的索引——它们可能对您的查询时间没有帮助,而且肯定会占用大量空间。

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

于 2008-12-30T23:33:30.303 回答
3

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

于 2008-12-30T21:57:06.020 回答
2

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

于 2008-12-30T21:08:56.710 回答
1

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

否则,我建议您主要以压缩格式存储数据并即时解压缩。

于 2008-12-30T20:59:13.923 回答
1

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

于 2008-12-30T21:01:53.200 回答
1

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

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

EDIT2:阅读有关SQLite 数据类型的文档,您似乎可以使“签名”字段跨越 26 个 INTEGER 类型的列,并且 SQLite 会做正确的事情,并且只使用存储所需的尽可能多的位价值。

于 2008-12-30T21:13:31.897 回答
0

我是否正确地认为您的数据库中有大约 45 万个这样的单词?

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

等等...您是否使用该签名来允许全文搜索或误输入识别?sqlite 上的全文搜索不会使该字段过时吗?

于 2008-12-30T21:06:21.460 回答
0

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

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

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

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

于 2008-12-30T21:47:45.977 回答
0

嗯...... iPhone......它没有永久数据连接吗?我认为这是一个 web 应用程序/web 服务可以很好地融入其中的地方。将您的大部分业务逻辑移动到网络服务器(他将拥有真正的 SQL 和 FTS 和 looooots 内存)并将该信息在线获取到设备上的客户端。

于 2008-12-30T21:53:42.690 回答
0

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

我会考虑对单词进行简单的压缩,霍夫曼编码非常适合这种事情。另外,我会查看签名:按字母频率顺序对列进行排序,不要费心存储尾随零,这可能是暗示的。我想你也可以对这些进行霍夫曼编码。

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

于 2008-12-31T14:07:47.980 回答