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
参数优化。
测试结果
对LevelDB
和ForestDB
进行简单的性能测试。
两个都在单线程
下进行10000
次的增删查改
测试,共测试5次。(这里测试的次数有点少,应该测试十万次以上的)
测试的时候可以发现(设置断点),Forest每次操作都将数据缓存在内存了,内存占用比较大。而LevelDB在添加的时候并没有缓存,但是在数据获取和修改的时候内存会变大。
总体上LevelDB占用内存小一点,但是linux下速度不及ForestDB(非常接近)。易用程度上,LevelB简单得多。磁盘占用的情况的话,Forest对磁盘使用比较少,这10000条数据占了13MB左右,而LevelDB则占了120MB左右。
Windows下测试结果#
Linux下测试结果#
测试代码
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!