对于许多应用程序,数据库是随机访问的,交互方式
或与“交易”。如果您有数据进入,这可能会发生
从网络服务器。但是,您通常必须填充大量
数据库一次,作为“批处理”操作。如果您可能会发生这种情况
正在进行数据分析项目,或将旧数据库迁移到
新格式。
当您一次填充数据库时,B-Tree 或其他
排序索引更可取,因为它允许批量插入
更有效地完成。这是通过排序来实现的
将密钥放入数据库之前。填充 BerkeleyDB
具有 1000 万个条目的数据库可能需要一个小时
是未排序的,因为每次访问都是缓存未命中。但是当
条目被排序,同样的过程可能只需要十分钟。
连续键的接近意味着您将使用各种
缓存几乎所有的插入。排序可以做的很
速度快,因此整个操作可以加快数倍
通过在插入数据之前对数据进行排序。使用哈希表索引,
因为您事先不知道每个键旁边会出现哪些键
其他的,这个优化是不可能的。
更新:我决定提供一个实际示例。它基于
以下脚本“db-test”
#!/usr/bin/perl
use warnings;
use strict;
use BerkeleyDB;
my %hash;
unlink "test.db";
tie %hash, (shift), -Filename=>"test.db", -Flags=>DB_CREATE or die;
while(<>) { $hash{$_}=1; }
untie %hash;
我们可以使用包含 1600 万个条目的 Wikipedia 转储索引文件对其进行测试。 (我在 800MHz 2 核笔记本电脑上运行此程序,内存为 3G)
$ >enw.tab bunzip2 <enwiki-20151102-pages-articles-multistream-index.txt.bz2
$ wc -l enw.tab
16050432 enw.tab
$ du -shL enw.tab
698M enw.tab
$ time shuf enw.tab > test-shuf
16.05s user 6.65s system 67% cpu 33.604 total
$ time sort enw.tab > test-sort
70.99s user 10.77s system 114% cpu 1:11.47 total
$ time ./db-test BerkeleyDB::Btree < test-shuf
682.75s user 368.58s system 42% cpu 40:57.92 total
$ du -sh test.db
1.3G test.db
$ time ./db-test BerkeleyDB::Btree < test-sort
378.10s user 10.55s system 91% cpu 7:03.34 total
$ du -sh test.db
923M test.db
$ time ./db-test BerkeleyDB::Hash < test-shuf
672.21s user 387.18s system 39% cpu 44:11.73 total
$ du -sh test.db
1.1G test.db
$ time ./db-test BerkeleyDB::Hash < test-sort
665.94s user 376.65s system 36% cpu 46:58.66 total
$ du -sh test.db
1.1G test.db
您可以看到对 Btree 键进行预排序会降低插入时间
从 41 分钟缩短到 7 分钟。排序只需要 1 分钟,所以
有很大的净收益 - 数据库创建速度提高了 5 倍。和
Hash 格式,创建时间同样慢
是否排序。另请注意,数据库文件大小较小
排序的插入;大概这与树平衡有关。
加速一定是由于某种缓存,但我不确定
在哪里。很可能我们在内核的缓存未命中率较低
带有排序插入的页面缓存。这将与
CPU 使用率 - 当页面缓存未命中时,进程
从磁盘检索页面时必须等待,因此 CPU 使用率是
更低。
为了比较,我还对两个较小的文件进行了相同的测试。
File | WP index | Wikt. words | /usr/share/dict/words
Entries | 16e6 | 4.7e6 | 1.2e5
Size | 700M | 65M | 1.1M
shuf time | 34s | 4s | 0.06s
sort time | 1:10s | 6s | 0.12s
-------------------------------------------------------------------------
| total DB CPU | |
| time size usage| |
-------------------------------------------------------------------------
Btree shuf | 41m, 1.3G, 42% | 5:00s, 180M, 88% | 6.4s, 3.9M, 86%
sort | 7m, 920M, 91% | 1:50s, 120M, 99% | 2.9s, 2.6M, 97%
Hash shuf | 44m, 1.1G, 39% | 5:30s, 129M, 87% | 6.2s, 2.4M, 98%
sort | 47m, 1.1G, 36% | 5:30s, 129M, 86% | 6.2s, 2.4M, 94%
-------------------------------------------------------------------------
Speedup | 5x | 2.7x | 2.2x
对于最大的数据集,排序插入为我们提供了 5 倍的加速。
用最小的,我们仍然得到 2 倍的加速 - 即使数据
很容易放入内存中,因此 CPU 使用率始终很高。这似乎
暗示我们正在从另一个效率来源中受益
除了页面缓存,5x 加速实际上是由于
与页面缓存和其他内容相等 - 也许更好
树平衡?
无论如何,我更喜欢 Btree 格式,因为它允许
更快的批处理操作。即使最终数据库在
随机,我使用批处理操作进行开发、测试和
维护。如果我能找到加快这些速度的方法,生活会更轻松。