2

我正在尝试使用 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);
    }

}

也许你可以告诉我为什么一段时间后“放置”操作需要越来越长的时间,也许你可以告诉我如何解决这个问题。

谢谢你的帮助,安德烈亚斯

4

4 回答 4

3

您可能希望查看 db_stat 实用程序提供的信息以及可用的特定于 HASH 的调整函数。请参阅关于配置 HASH 数据库的 BDB 参考指南部分

我希望您在商用硬件上每秒获得成千上万的插入。您正在经历什么,您的绩效目标是什么?

问候,

戴夫

于 2010-06-02T02:48:51.063 回答
3

我建议尝试批量插入 API,您可以在此处的文档中阅读相关信息: http ://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/CXX/dbput.html#put_DB_MULTIPLE_KEY

另外,我猜你对 memp_trickle 的调用是造成大部分减速的原因。随着缓存变得越来越脏,寻找要涓流的页面变得更加昂贵。实际上,由于您只是在写入,因此拥有大缓存只会造成伤害(一旦写入数据,您就不会再次使用它,因此您不希望它在缓存中徘徊。)我会推荐测试不同的(较小的)缓存大小。

最后,如果您唯一关心的是插入性能,则使用更大的页面大小会有所帮助。您将能够在每个页面上放置更多数据,这将导致更少的磁盘写入。

-本

于 2010-06-02T20:33:53.930 回答
1

memp_trickle 几乎可以肯定会减慢速度。使用涓涓细流通常很好,但它属于自己的线程才能有效。BDB(除非您进入更高级别的复制 API)不会为您创建线程——幕后没有任何事情发生(线程方面)。当您从缓存中强制使用脏页时,trickle 将有效(查看统计输出以查看是否发生了这种情况)。

您也可以考虑使用 BTREE 而不是 HASH。是的,我知道你特别提到了哈希,但为什么呢?如果您希望最大限度地提高性能,为什么要添加该限制?您可能能够利用参考的位置来减少缓存占用空间 - 您相信通常有更多的位置,或者您可以创建一些 - 如果您生成随机数字的密钥,例如,在日期之前和时间。这通常将局部性引入感知的“随机”系统。如果您确实使用 btree,则需要注意系统密钥的字节顺序(在 Wikipedia 中查找 Endianness),如果您使用的是 Little Endian 系统,则需要交换字节。使用具有正确顺序和引入位置的 BTREE 意味着您的键/值对将存储在 ' key-generation-time' 顺序,因此如果您看到最近的键上的最多操作,您将倾向于一遍又一遍地点击相同的页面(查看您的统计数据中的缓存命中率)。所以你需要更少的缓存。另一种思考方式是在缓存数量相同的情况下,您的解决方案将按更大的倍数进行扩展。

我希望您的实际应用程序确实不会按顺序插入整数键(如果这样做,您会很幸运)。因此,您应该编写一个密切模拟您的访问模式的基准测试,至少在以下方面:密钥大小、数据大小、访问模式、数据库中的项目数、读/写混合。一旦你有了这些,看看统计数据——密切关注任何暗示 IO 或争用的东西。

顺便说一句,我最近在http://libdb.wordpress.com上开了一个博客来讨论 BDB 性能调整(以及其他与 BDB 相关的问题)。你可能会在那里得到一些好主意。根据您进行的调整类型,延迟和吞吐量可能存在巨大差异。特别是,请参阅http://libdb.wordpress.com/2011/01/31/revving-up-a-benchmark-from-626-to-74000-operations-per-second/

于 2010-10-27T16:43:02.810 回答
0

您的性能下降可能有几个原因,这些原因实际上与您的代码无关。我可能弄错了,但我认为这都是关于内部数据库结构(和使用的数据结构)的。

想一想数据库使用哈希表以外的某种方法的情况,例如RB 树。在该树中插入将具有Big-O 意义,并且每个插入的元素都会增加下一次O(logN)插入所需的时间。

不幸的是,普通的hash-table也可能发生同样的情况,因此初始O(1)插入操作时间会降低到更糟的程度。这可能有几个原因,但都与哈希冲突有关,这可能是由于错误的哈希函数、错误的数据(这对当前使用的哈希函数不利)甚至是由于月相而发生的。

如果我是你,我会尝试深入研究你的数据库内部结构。另外,我认为用你的数据库以外的东西(例如boost::unordered_map)测试你的密钥也可能有利于你的测试和分析。

编辑:还要提一下,您是否尝试更改cache_size样本中的内容?或者也许还有一些其他与性能相关的参数可以修改?

于 2010-05-27T10:15:47.633 回答