零 环境说明:
所有的数据插入的都是Key=int,Value=int,在循环中递增的.
本机NTFS的默认簇大小为4K.
本机配置仅仅影响绝对值.相对值是可比较的:
OS=WinXP SP2;RAM=1G;CPU=AMD Athlon 64 X2 Dual 5000+;Disk=160G
测试的实际数据量为:300*10000*2*sizeof(int)/1024/1024~=22.89MByte
下面所有的测试结果的单位都是秒.
编译器:C++ builder 6.0(使用bcb编译BDB源码,形成LIB库后,直接链接到测试程序中.没有测试DLL的形式.)
BDB版本:4.6.21.NC
一 测试页尺寸对读写性能的影响:
记录数量 =300万 缓存尺寸=0M
读写\页尺寸 | 1K | 2K | 4K | 8K | 16K | 32K |
B+写 | 94.94 | 84.83 | 82.73 | 97.16 | 142.67 | 232.11 |
HASH写 | 346.16 | 320.41 | 288.36 | 295.19 | 599.66 | 867.03 |
B+读 | 4.22 | 4.06 | 3.86 | 3.91 | 3.80 | 3.78 |
HASH读 | 8.25 | 7.94 | 5.42 | 5.41 | 4.99 | 4.88 |
结论:页尺寸与文件系统的簇大小相同时,写入性能最佳,读取性能中等.
在0M缓存的时候,B+的性能要比HASH好得多.
二 测试cache缓存大小对读写性能的影响:
记录数量=300万 页尺寸=4K 真实数据量=22.89MByte 数据库文件大小=80M
读写\缓存 | 0M | 10M | 20M | 40M | 80M | 160M | 320M |
B+写 | 85.06 | 88.66 | 133.31 | 164.81 | 15.31 | 15.34 | 15.27 |
HASH写 | 292.91 | 224.47 | 180.76 | 95.28 | 20.11 | 20.06 | 20.05 |
B+读 | 3.98 | 4.17 | 4.86 | 9.56 | 3.83 | 3.81 | 3.80 |
HASH读 | 5.53 | 5.83 | 5.83 | 8.16 | 5.20 | 5.08 | 5.16 |
记录数量=600万 页尺寸=4K 真实数据量=45.78MByte 数据库文件大小=160M
读写\缓存 | 0M | 40M | 80M | 160M | 320M |
B+写 | 259.39 | 1198.27 | 1017.94 | 34.59 | 34.30 |
HASH写 | 1889.32 | 1279.95 | 563.12 | 40.67 | 40.89 |
B+读 | 7.89 | 14.02 | 22.84 | 7.97 | 8.03 |
HASH读 | 11.17 | 16.81 | 11.66 | 10.39 | 10.88 |
结论:
对于缓存大于数据库文件尺寸的时候,没有太多可说的,操作都在内存中,速度非常快.
对于大数据量的读取,两组对比都比较清晰的说明了一点:缓存的大小对读取记录的性能影响不是很大.
对于大数据量的写入,缓存对性能的影响就非常可观了,基本可以肯定的是,HASH库缓存越大写入速度越快. 而奇怪的是,B+库在缓存不足的时候,性能反而比0缓存时还要差很多!!
总的来说,在我的这些测试中,B+与HASH数据库的性能差异很大.
对于缓存大于物理内存的情况未做测试,估计对性能不会有好的影响,毕竟在这种情况下,效率的瓶颈都是在磁盘的IO上.
测试的核心代码如下:
Cpp代码
- #include <db_cxx.h>
- #define DATABASE "access.db"
-
- void run(int tcount,DBTYPE DbType,size_t psize,size_t csize)
- {
- remove(DATABASE);
- Db db(0, 0);
-
- db.set_errpfx("AccessExample");
- db.set_pagesize(1024*psize);
- db.set_cachesize(0, 1024*1024*csize, 0);
- db.open(NULL, DATABASE, NULL, DbType, DB_CREATE|DB_THREAD, 0664);
-
- int testcount=10000*tcount;
- size_t tick1=GetTickCount();
- for (int i=0;i<testcount;i++)
- {
- Dbt key(&i,sizeof(int));
- Dbt data(&i,sizeof(int));
- db.put(0, &key, &data, DB_NOOVERWRITE);
- }
-
- printf("插入结束 %d 万记录,全部用时:%.2f秒\r\n",tcount,(GetTickCount()-tick1)/(float)1000);
- tick1=GetTickCount();
- try
- {
- Dbc *dbcp;
- db.cursor(NULL, &dbcp, 0);
- Dbt key;
- Dbt data;
- while (dbcp->get(&key, &data, DB_NEXT) == 0)
- {
- key.get_data();
- data.get_data();
- }
- dbcp->close();
- printf("遍历结束 %d 万记录,全部用时:%.2f秒\r\n",tcount,(GetTickCount()-tick1)/(float)1000);
- db.sync(0);
- }
- catch (DbException &dbe) {}
- db.close(0);
- }
#include <db_cxx.h>
#define DATABASE "access.db"
//tcount=记录数为多少万次,DbType=数据库类型,psize=页尺寸K,csize=缓存尺寸M
void run(int tcount,DBTYPE DbType,size_t psize,size_t csize)
{
remove(DATABASE);
Db db(0, 0);
db.set_errpfx("AccessExample");
db.set_pagesize(1024*psize);
db.set_cachesize(0, 1024*1024*csize, 0);
db.open(NULL, DATABASE, NULL, DbType, DB_CREATE|DB_THREAD, 0664);
int testcount=10000*tcount;
size_t tick1=GetTickCount();
for (int i=0;i<testcount;i++)
{
Dbt key(&i,sizeof(int));
Dbt data(&i,sizeof(int));
db.put(0, &key, &data, DB_NOOVERWRITE);
}
printf("插入结束 %d 万记录,全部用时:%.2f秒\r\n",tcount,(GetTickCount()-tick1)/(float)1000);
tick1=GetTickCount();
try
{
Dbc *dbcp;
db.cursor(NULL, &dbcp, 0);
Dbt key;
Dbt data;
while (dbcp->get(&key, &data, DB_NEXT) == 0)
{
key.get_data();
data.get_data();
}
dbcp->close();
printf("遍历结束 %d 万记录,全部用时:%.2f秒\r\n",tcount,(GetTickCount()-tick1)/(float)1000);
db.sync(0);
}
catch (DbException &dbe) {}
db.close(0);
}
分享到:
关于一些中文分词器
评论
4 楼 h_rain 2009-02-22
结论:页尺寸与文件系统的簇大小相同时,写入性能最佳,读取性能中等.
缓存用尽后,性能的瓶颈就在于磁盘IO.
BDB内部对IO进行了优化,每次操作都是对"页尺寸"字节进行处理,就是说,读写10字节或100字节的时候,其实都是在"页尺寸"这么大的内存上进行读写,之后一次性将一个页写入磁盘.你给定的页尺寸是8k,但ntfs默认的"簇"大小是4k,所以这样的操作要跨簇进行,效率就低了.
建议根据文件系统的"簇"大小设置BDB的"页尺寸".
这样的话,耗时基本是定长的了.
3 楼 peter_wu 2009-02-20
观察任务管理器,发现速度快的时候,cache还没有用完,没有IO操作。当内存不再增长,cache用完的时候,IO开始大量读取和写入,速度开始下降。原来如此啊。
2 楼 peter_wu 2009-02-20
插入一个周期,10w 用时 0.00 秒
插入一个周期,10w 用时 0.92 秒
插入一个周期,10w 用时 1.09 秒
插入一个周期,10w 用时 1.11 秒
插入一个周期,10w 用时 1.14 秒
插入一个周期,10w 用时 1.16 秒
插入一个周期,10w 用时 1.19 秒
插入一个周期,10w 用时 1.14 秒
插入一个周期,10w 用时 1.19 秒
插入一个周期,10w 用时 1.20 秒
插入一个周期,10w 用时 1.20 秒
插入一个周期,10w 用时 1.28 秒
插入一个周期,10w 用时 1.22 秒
插入一个周期,10w 用时 1.17 秒
插入一个周期,10w 用时 1.20 秒
插入一个周期,10w 用时 1.19 秒
插入一个周期,10w 用时 1.20 秒
插入一个周期,10w 用时 1.26 秒
插入一个周期,10w 用时 1.24 秒
插入一个周期,10w 用时 1.16 秒
插入一个周期,10w 用时 1.17 秒
插入一个周期,10w 用时 1.38 秒
插入一个周期,10w 用时 1.19 秒
插入一个周期,10w 用时 1.20 秒
插入一个周期,10w 用时 1.16 秒
插入一个周期,10w 用时 1.19 秒
插入一个周期,10w 用时 1.17 秒
插入一个周期,10w 用时 1.22 秒
插入一个周期,10w 用时 1.17 秒
插入一个周期,10w 用时 1.20 秒
插入一个周期,10w 用时 1.22 秒
插入一个周期,10w 用时 1.28 秒
插入一个周期,10w 用时 1.19 秒
插入一个周期,10w 用时 1.33 秒
插入一个周期,10w 用时 1.19 秒
插入一个周期,10w 用时 1.23 秒
插入一个周期,10w 用时 1.22 秒
插入一个周期,10w 用时 1.20 秒
插入一个周期,10w 用时 1.22 秒
插入一个周期,10w 用时 1.23 秒
插入一个周期,10w 用时 1.42 秒
插入一个周期,10w 用时 1.22 秒
插入一个周期,10w 用时 1.19 秒
插入一个周期,10w 用时 1.27 秒
插入一个周期,10w 用时 5.84 秒
插入一个周期,10w 用时 9.52 秒
插入一个周期,10w 用时 14.03 秒
插入一个周期,10w 用时 15.39 秒
插入一个周期,10w 用时 16.44 秒
插入一个周期,10w 用时 20.39 秒
插入结束 500 万记录,全部用时:156.05秒
遍历结束 500 万记录,全部用时:14.11秒
请按任意键继续. . .
1 楼 peter_wu 2009-02-20
我改了下代码,发现一个问题,随着时间推移,插入效率下降严重,请问是为什么。
Java代码
- #include <db_cxx.h>
- #include <Windows.h>
- #define DATABASE "access.db"
- void run(int tcount,DBTYPE DbType,size_t psize,size_t csize) ;
- void main(int argc,char * argv[])
- {
- run(500,DB_BTREE,8,100);
- }
-
-
-
- void run(int tcount,DBTYPE DbType,size_t psize,size_t csize)
- {
- remove(DATABASE);
- Db db(0, 0);
-
- db.set_errpfx("AccessExample");
- db.set_pagesize(1024*psize);
- db.set_cachesize(0, 1024*1024*csize, 0);
- db.open(NULL, DATABASE, NULL, DbType, DB_CREATE|DB_THREAD, 0664);
-
- int testcount=10000*tcount;
- size_t tick1=GetTickCount();
-
- DWORD inlinetick=tick1;
- for (int i=0;i<testcount;i++)
- {
- Dbt key(&i,sizeof(int));
- Dbt data(&i,sizeof(int));
- db.put(0, &key, &data, DB_NOOVERWRITE);
- if (i%100000==0)
- {
- printf("插入一个周期,10w 用时 %.2f 秒\n",(GetTickCount()-inlinetick)/(float)1000);
- inlinetick=GetTickCount();
- }
- }
-
- printf("插入结束 %d 万记录,全部用时:%.2f秒\r\n",tcount,(GetTickCount()-tick1)/(float)1000);
- tick1=GetTickCount();
- try
- {
- Dbc *dbcp;
- db.cursor(NULL, &dbcp, 0);
- Dbt key;
- Dbt data;
- while (dbcp->get(&key, &data, DB_NEXT) == 0)
- {
- key.get_data();
- data.get_data();
- }
- dbcp->close();
- printf("遍历结束 %d 万记录,全部用时:%.2f秒\r\n",tcount,(GetTickCount()-tick1)/(float)1000);
- db.sync(0);
- }
- catch (DbException &dbe) {}
- db.close(0);
- }