LevelDB和ForestDB簡單性能測試(含代碼)


測試環境簡單說明

Windows下測試

硬件環境如下:
處理器:Intel(R) Core(TM) i5-4460 CPU @ 3.20GHz
內 存:8GB
硬 盤:希捷 ST1000DM003
操作系統:Windows 10 企業版
編譯說明:
兩個都是使用VS2015編譯的64位Release版本。運行時庫采用動態多線程版本(MD)

Linux下測試

硬件環境如下:
處理器:Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz
內 存:8GB
硬 盤:金士頓64G SSD
操作系統:ArchLinux (Linux version 4.8.13-1-ARCH)
編譯說明:
兩個都是使用Gcc 6.2.1編譯的x64版本,使用-O2參數優化。

測試結果

LevelDBForestDB進行簡單的性能測試。
兩個都在單線程下進行10000次的增刪查改測試,共測試5次。(這里測試的次數有點少,應該測試十萬次以上的)
測試的時候可以發現(設置斷點),Forest每次操作都將數據緩存在內存了,內存占用比較大。而LevelDB在添加的時候並沒有緩存,但是在數據獲取和修改的時候內存會變大。
總體上LevelDB占用內存小一點,但是linux下速度不及ForestDB(非常接近)。易用程度上,LevelB簡單得多。磁盤占用的情況的話,Forest對磁盤使用比較少,這10000條數據占了13MB左右,而LevelDB則占了120MB左右。

Windows下測試結果

測試結果平均值對比直方圖:
測試結果對比直方圖

LevelDB 測試結果截圖
LevelDB 測試結果截圖

ForestDB 測試結果截圖
ForestDB 測試結果截圖

Linux下測試結果

測試結果平均值對比直方圖:
測試結果對比直方圖

LevelDB 測試結果截圖
LevelDB 測試結果截圖

ForestDB 測試結果截圖
ForestDB 測試結果截圖

測試代碼

LevelDB測試代碼

#include <cassert>  
#include <string>  
#include <iostream>
#include <chrono>

#include "leveldb/db.h"  

#define TEST_FREQUENCY	(10000)

char* randomstr()
{
	static char buf[1024];
	int len = rand() % 768 + 255;
	for (int i = 0; i < len; ++i) {
		buf[i] = 'A' + rand() % 26;
	}
	buf[len] = '\0';
	return buf;
}

int main() 
{
	leveldb::DB* db;
	leveldb::Options options;
	options.create_if_missing = true;

	// 打開數據庫
	leveldb::Status status = leveldb::DB::Open(options, "./testdb", &db);
	assert(status.ok());

	srand(2017);
	std::string k[TEST_FREQUENCY];
	for (int i = 0; i < TEST_FREQUENCY; ++i) {
		k[i] = (randomstr());
	}
	std::string v("壹貳叄肆伍陸柒捌玖拾");
	v.append(v).append(v).append(v).append(v).append(v);

	// 測試添加
	{
		auto start = std::chrono::system_clock::now();
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			status = db->Put(leveldb::WriteOptions(), k[i], v);
			assert(status.ok());
		}
		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

		std::cout << TEST_FREQUENCY <<"次添加耗時: "
			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
			<< "秒" << std::endl;
	}
	// 測試獲取
	{
		auto start = std::chrono::system_clock::now();
		std::string v2[TEST_FREQUENCY];
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			status = db->Get(leveldb::ReadOptions(), k[i], &v2[i]);
			assert(status.ok());
		}
		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

		std::cout << TEST_FREQUENCY <<"次獲取耗時: "
			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
			<< "秒" << std::endl;
		// 驗證獲取結果是否正確
		std::string ss;
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			if (v2[i] != v) {
				std::cout << "第 " << i << " 個結果不正確" << std::endl;
				std::cout << v2[i] << std::endl;
			}
		}
	}
	// 測試修改
	{
		auto start = std::chrono::system_clock::now();
		v.append(v);
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			status = db->Put(leveldb::WriteOptions(), k[i], v);
			assert(status.ok());
		}
		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

		std::cout << TEST_FREQUENCY <<"次修改耗時: "
			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
			<< "秒" << std::endl;
	}

	// 測試刪除
	{
		auto start = std::chrono::system_clock::now();
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			status = db->Delete(leveldb::WriteOptions(), k[i]);
			assert(status.ok());
		}
		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

		std::cout << TEST_FREQUENCY <<"次刪除耗時: "
			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
			<< "秒" << std::endl;
	}
	delete db;
	return 0;
}

Forest 測試代碼

#include <cassert>  
#include <string>  
#include <iostream>
#include <chrono>

#include "libforestdb/forestdb.h"

#define TEST_FREQUENCY	(10000)

char* randomstr()
{
	static char buf[1024];
	int len = rand() % 768 + 255;
	for (int i = 0; i < len; ++i) {
		buf[i] = 'A' + rand() % 26;
	}
	buf[len] = '\0';
	return buf;
}

int main()
{
	fdb_file_handle* fdbFileHandle = nullptr;
	fdb_kvs_handle* fdbKvsHandle = nullptr;
	fdb_status status;

	// 初始化ForestDB
	// 1、文件配置設置配置
	fdb_config fileConfig = fdb_get_default_config();
	{// WAL閾值4K
		fileConfig.wal_threshold = 4096;
		// 緩存大小64MB
		fileConfig.buffercache_size = 64 * 1024 * 1024;
		// 設置使用默認的kvs
		fileConfig.multi_kv_instances = false;
		// 關閉循環塊復用
		fileConfig.block_reusing_threshold = 100;
		// 使用序列樹
		fileConfig.seqtree_opt = FDB_SEQTREE_USE;
	}
	// 2、使用設置的配置進行初始化
	status = fdb_init(&fileConfig);
	assert(status == FDB_RESULT_SUCCESS);

	// 打開數據庫
	status = fdb_open(&fdbFileHandle, "./testdb", &fileConfig);
	assert(status == FDB_RESULT_SUCCESS);
	// 打開kvs
	fdb_kvs_config kvsConfig = fdb_get_default_kvs_config();
	status = fdb_kvs_open_default(fdbFileHandle, &fdbKvsHandle, &kvsConfig);
	assert(status == FDB_RESULT_SUCCESS);


	srand(2017);
	std::string k[TEST_FREQUENCY];
	for (int i = 0; i < TEST_FREQUENCY; ++i) {
		k[i] = (randomstr());
	}
	std::string v("壹貳叄肆伍陸柒捌玖拾");
	v.append(v).append(v).append(v).append(v).append(v);

	// 測試添加
	{
		auto start = std::chrono::system_clock::now();
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			status = fdb_set_kv(fdbKvsHandle, k[i].data(), k[i].size(), v.data(), v.size());
			assert(status == FDB_RESULT_SUCCESS);
		}
		// 提交操作到磁盤(這里必須commit才能實際寫入到磁盤)
		fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);

		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
	
		std::cout << TEST_FREQUENCY <<"次添加耗時: "
			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
			<< "秒" << std::endl;
	}
	// 測試獲取
	{
		auto start = std::chrono::system_clock::now();
		void* v2[TEST_FREQUENCY]; size_t v2len[TEST_FREQUENCY];
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			status = fdb_get_kv(fdbKvsHandle, k[i].data(), k[i].size(), &v2[i], &v2len[i]);
			assert(status == FDB_RESULT_SUCCESS);
		}
		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

		std::cout << TEST_FREQUENCY <<"次獲取耗時: "
			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
			<< "秒" << std::endl;
		// 驗證獲取結果是否正確
		std::string ss;
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			ss.assign((const char*)v2[i], v2len[i]);
			if (ss != v) {
				std::cout << "第 " << i << " 個結果不正確" << std::endl;
				std::cout << ss << std::endl;
			}
			free(v2[i]);
		}
	}
	// 測試修改
	{
		auto start = std::chrono::system_clock::now();
		v.append(v);
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			status = fdb_set_kv(fdbKvsHandle, k[i].data(), k[i].size(), v.data(), v.size());
			assert(status == FDB_RESULT_SUCCESS);
		}
		// 提交操作到磁盤(這里必須commit才能實際寫入到磁盤)
		fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);

		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

		std::cout << TEST_FREQUENCY <<"次修改耗時: "
			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
			<< "秒" << std::endl;
	}

	// 測試刪除
	{
		auto start = std::chrono::system_clock::now();
		for (int i = 0; i < TEST_FREQUENCY; ++i) {
			status = fdb_del_kv(fdbKvsHandle, k[i].data(), k[i].size());
			assert(status == FDB_RESULT_SUCCESS);
		}
		// 提交操作到磁盤(這里必須commit才能實際寫入到磁盤)
		fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);

		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

		std::cout << TEST_FREQUENCY <<"次刪除耗時: "
			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
			<< "秒" << std::endl;
	}
	
	// 關閉數據庫
	status = fdb_kvs_close(fdbKvsHandle);
	assert(status == FDB_RESULT_SUCCESS);
	status = fdb_close(fdbFileHandle);
	assert(status == FDB_RESULT_SUCCESS);
	status = fdb_shutdown();
	assert(status == FDB_RESULT_SUCCESS);
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM