零 環境說明:
所有的數據插入的都是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);
- }