我正在尝试使用berkeley db构建一个哈希值,它应包含许多元组(大约18GB的键值对),但在我的所有测试中,插入操作的性能会随着时间的推移而显着下降。我编写了这个脚本来测试性能:
#include<iostream>
#include<db_cxx.h>
#include<ctime>
#define MILLION 1000000
int main () {
long long a = 0;
long long b = 0;
int passes = 0;
int i = 0;
u_int32_t flags = DB_CREATE;
Db* dbp = new Db(NULL,0);
dbp->set_cachesize( 0, 1024 * 1024 * 1024, 1 );
int ret = dbp->open(
NULL,
"test.db",
NULL,
DB_HASH,
flags,
0);
time_t time1 = time(NULL);
while ( passes < 100 ) {
while( i < MILLION ) {
Dbt key( &a, sizeof(long long) );
Dbt data( &b, sizeof(long long) );
dbp->put( NULL, &key, &data, 0);
a++; b++; i++;
}
DbEnv* dbep = dbp->get_env();
int tmp;
dbep->memp_trickle( 50, &tmp );
i=0;
passes++;
std::cout << "Inserted one million --> pass: " << passes << " took: " << time(NULL) - time1 << "sec" << std::endl;
time1 = time(NULL);
}
}
也许你可以告诉我为什么一段时间后“放”操作需要越来越长的时间,以及如何解决这个问题。
感谢您的帮助, 安德烈亚斯
答案 0 :(得分:3)
您可能希望查看db_stat实用程序提供的信息以及可用的特定于HASH的调整功能。请参阅BDB Reference Guide section on configuring a HASH database。
我希望你能在商用硬件上每秒获得数十万次插入。您有什么体验?您的表现目标是什么?
问候,
戴夫
答案 1 :(得分:3)
我建议您尝试批量插入API,您可以在此处的文档中阅读: http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/CXX/dbput.html#put_DB_MULTIPLE_KEY
另外,我猜你对memp_trickle的调用是造成大部分减速的原因。随着缓存变得更脏,找到要滴流的页面变得更加昂贵。事实上,由于你只是写作,只有大缓存才会受到伤害(一旦你编写了数据,你就不再使用它了,所以你不希望它在缓存中闲逛。)我会建议测试不同(较小)的缓存大小。
最后,如果您唯一关心的是插入性能,那么使用更大的页面大小将有所帮助。您将能够在每个页面上容纳更多数据,这将导致更少的磁盘写入。
-Ben
答案 2 :(得分:1)
memp_trickle几乎肯定会减慢速度。使用涓流通常很好,但它属于自己的线程才有效。 BDB(除非你进入更高级别的复制API)为你创建没有线程 - 在幕后没有任何事情发生(线程方面)。当您从缓存中强制执行脏页时,涓流将会有效(查看统计输出以查看是否发生了这种情况)。
您也可以考虑使用BTREE而不是HASH。是的,我知道你特意说哈希,但为什么呢?如果您希望最大限度地提高性能,为什么要添加该限制?您可以利用引用的局部性来减少缓存占用空间 - 通常会有更多的局部性,或者您可以创建一些 - 如果生成随机数字的键,例如,在日期之前和时间。这通常会将地点引入感知的“随机”系统。如果您确实使用btree,则需要注意系统密钥的字节顺序(在维基百科中查找Endianness),如果您使用的是Little Endian系统,则需要交换字节。使用具有正确排序和引入位置的BTREE意味着您的键/值对将以“密钥生成时间”顺序存储,因此如果您在最近的密钥上看到最多的操作,您将倾向于访问相同的页面一遍又一遍(请参阅统计信息中的缓存命中率)。所以你需要更少的缓存。考虑它的另一种方法是使用相同的缓存量,您的解决方案将按更大的倍数进行扩展。
我希望你的实际应用程序真的不会按顺序插入整数键(如果有的话,你会很幸运)。因此,您应该编写一个非常接近模拟访问模式的基准测试,至少在以下方面:密钥大小,数据大小,访问模式,数据库中的项目数,读/写的混合。一旦你有了这个,看看统计数据 - 密切关注任何暗示IO或争用的事情。
BTW,我最近在http://libdb.wordpress.com开了一个博客来讨论BDB性能调优(以及与BDB相关的其他事项)。你可能会在那里得到一些好主意。根据您的调整类型,延迟和吞吐量可能存在巨大差异。特别是,请参阅http://libdb.wordpress.com/2011/01/31/revving-up-a-benchmark-from-626-to-74000-operations-per-second/答案 3 :(得分:0)
您的性能下降可能有多种原因,这些原因实际上与您的代码无关。我可能弄错了,但我认为这完全是关于内部数据库结构(并使用 数据结构 )。
考虑数据库使用除哈希表之外的某种方法的情况,例如 RB树。插入该树将在Big-O意义上采用O(logN)
,并且每个插入的元素都会增加 next 插入所需的时间。
不幸的是,使用普通的哈希表会发生同样的情况,因此初始O(1)
插入操作时间会降低到更糟糕的程度。这可能有几个原因,但这都是关于哈希冲突,这可能是由于错误的哈希函数,错误的数据(对于当前使用的哈希函数错误)甚至是由于月相。
如果我是你,我会尝试挖掘你的数据库内部结构。此外,我认为使用除数据库以外的其他方式测试您的密钥(例如boost::unordered_map
)也可能有益于您的测试和分析。
编辑:还要提一下,您是否尝试更改样本中的cache_size
内容?或者可能还有一些其他与性能相关的参数可以修改?