|
|
@ -0,0 +1,180 @@ |
|
|
|
#include <iostream>
|
|
|
|
#include <cassert>
|
|
|
|
#include <vector>
|
|
|
|
#include <chrono>
|
|
|
|
#include <leveldb/db.h>
|
|
|
|
|
|
|
|
using namespace std::chrono; |
|
|
|
|
|
|
|
// 定义字段
|
|
|
|
struct Field { |
|
|
|
std::string first; |
|
|
|
std::string second; |
|
|
|
}; |
|
|
|
|
|
|
|
// 解析数据值
|
|
|
|
std::vector<std::pair<std::string, std::string>> ParseValue(const std::string& value) { |
|
|
|
std::vector<std::pair<std::string, std::string>> fields; |
|
|
|
size_t start = 0; |
|
|
|
size_t end = value.find("|"); |
|
|
|
|
|
|
|
while (end != std::string::npos) { |
|
|
|
std::string field = value.substr(start, end - start); |
|
|
|
size_t separator = field.find(":"); |
|
|
|
|
|
|
|
if (separator != std::string::npos) { |
|
|
|
fields.push_back({field.substr(0, separator), field.substr(separator + 1)}); |
|
|
|
} |
|
|
|
|
|
|
|
start = end + 1; |
|
|
|
end = value.find("|", start); |
|
|
|
} |
|
|
|
|
|
|
|
return fields; |
|
|
|
} |
|
|
|
|
|
|
|
// 查询函数:根据字段查找所有包含该字段的 Key
|
|
|
|
std::vector<std::string> FindKeysByField(leveldb::DB* db, const Field& field) { |
|
|
|
std::vector<std::string> keys; |
|
|
|
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); |
|
|
|
|
|
|
|
for (it->SeekToFirst(); it->Valid(); it->Next()) { |
|
|
|
std::string key = it->key().ToString(); |
|
|
|
std::string value = it->value().ToString(); |
|
|
|
|
|
|
|
std::vector<std::pair<std::string, std::string>> fields = ParseValue(value); |
|
|
|
|
|
|
|
// 查找是否有匹配的字段
|
|
|
|
for (const auto& f : fields) { |
|
|
|
if (f.first == field.first && f.second == field.second) { |
|
|
|
keys.push_back(key); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
delete it; |
|
|
|
return keys; |
|
|
|
} |
|
|
|
|
|
|
|
// 生成数据并插入数据库
|
|
|
|
void GenerateAndInsertData(leveldb::DB* db, int num_entries) { |
|
|
|
leveldb::WriteOptions write_options; |
|
|
|
leveldb::Status status; |
|
|
|
|
|
|
|
for (int i = 1; i <= num_entries; ++i) { |
|
|
|
std::string key = "k_" + std::to_string(i); |
|
|
|
std::string name = "Customer#" + std::to_string(i); |
|
|
|
std::string address = "Address_" + std::to_string(i); |
|
|
|
std::string phone = "25-989-741-" + std::to_string(1000 + i); |
|
|
|
|
|
|
|
std::string value = "name:" + name + "|address:" + address + "|phone:" + phone; |
|
|
|
|
|
|
|
status = db->Put(write_options, key, value); |
|
|
|
assert(status.ok() && "Failed to insert data"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 基准测试:二级索引性能提升
|
|
|
|
void BenchmarkFieldQueryWithIndex(leveldb::DB* db) { |
|
|
|
// 测试前,查询无索引的字段性能
|
|
|
|
auto start = high_resolution_clock::now(); |
|
|
|
Field field = {"name", "Customer#10000"}; |
|
|
|
std::vector<std::string> keys_without_index = FindKeysByField(db, field); |
|
|
|
auto end = high_resolution_clock::now(); |
|
|
|
auto duration = duration_cast<microseconds>(end - start); |
|
|
|
std::cout << "Time without index: " << duration.count() << " microseconds" << std::endl; |
|
|
|
|
|
|
|
// 创建二级索引
|
|
|
|
// 在此添加创建索引的代码(可以使用 DBImpl::CreateIndexOnField 函数)
|
|
|
|
start = high_resolution_clock::now(); |
|
|
|
leveldb::Status status = db->CreateIndexOnField("name"); |
|
|
|
end = high_resolution_clock::now(); |
|
|
|
duration = duration_cast<microseconds>(end - start); |
|
|
|
std::cout << "Time to create index: " << duration.count() << std::endl; |
|
|
|
|
|
|
|
// 测试后,查询有索引的字段性能
|
|
|
|
start = high_resolution_clock::now(); |
|
|
|
std::vector<std::string> keys_with_index = db->QueryByIndex("name:Customer#10000"); // 使用二级索引查询
|
|
|
|
end = high_resolution_clock::now(); |
|
|
|
duration = duration_cast<microseconds>(end - start); |
|
|
|
std::cout << "Time with index: " << duration.count() << " microseconds" << std::endl; |
|
|
|
|
|
|
|
// 输出查询结果
|
|
|
|
std::cout << "Found " << keys_with_index.size() << " keys with index." << std::endl; |
|
|
|
assert(!keys_with_index.empty() && "Query by index returned no results"); |
|
|
|
|
|
|
|
std::cout << "Query by index results for name=Customer#10000: "; |
|
|
|
for (const auto& result : keys_with_index) { |
|
|
|
std::cout << result << ", "; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 基准测试:记录插入时的性能影响
|
|
|
|
void BenchmarkWritePerformance(leveldb::DB* db, int num_entries) { |
|
|
|
leveldb::WriteOptions write_options; |
|
|
|
auto start = high_resolution_clock::now(); |
|
|
|
|
|
|
|
GenerateAndInsertData(db, num_entries); // 执行批量插入
|
|
|
|
|
|
|
|
auto end = high_resolution_clock::now(); |
|
|
|
auto duration = duration_cast<microseconds>(end - start); |
|
|
|
std::cout << "Insertion time for " << num_entries << " entries: " << duration.count() << " microseconds" << std::endl; |
|
|
|
} |
|
|
|
|
|
|
|
// 基准测试:记录删除二级索引的开销
|
|
|
|
void BenchmarkDeleteIndex(leveldb::DB* db, const std::string& field_name) { |
|
|
|
auto start = high_resolution_clock::now(); |
|
|
|
|
|
|
|
// 删除二级索引
|
|
|
|
leveldb::Status status = db->DeleteIndex(field_name); |
|
|
|
assert(status.ok() && "Failed to delete index"); |
|
|
|
|
|
|
|
auto end = high_resolution_clock::now(); |
|
|
|
auto duration = duration_cast<microseconds>(end - start); |
|
|
|
std::cout << "Time to delete index on field '" << field_name << "': " << duration.count() << " microseconds" << std::endl; |
|
|
|
} |
|
|
|
|
|
|
|
// 获取数据库大小(用来估算二级索引的空间占用)
|
|
|
|
void GetDatabaseSize(leveldb::DB* db) { |
|
|
|
std::string property; |
|
|
|
|
|
|
|
// 使用 bool 返回值检查是否成功获取属性
|
|
|
|
bool success = db->GetProperty("leveldb.stats", &property); |
|
|
|
if (!success) { |
|
|
|
std::cerr << "Failed to get db stats" << std::endl; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
std::cout << "Database stats: " << std::endl; |
|
|
|
std::cout << property << std::endl; |
|
|
|
} |
|
|
|
|
|
|
|
int main() { |
|
|
|
leveldb::Options options; |
|
|
|
options.create_if_missing = true; |
|
|
|
|
|
|
|
// 打开数据库
|
|
|
|
leveldb::DB* db = nullptr; |
|
|
|
leveldb::Status status = leveldb::DB::Open(options, "./testdb", &db); |
|
|
|
assert(status.ok() && "Failed to open database"); |
|
|
|
|
|
|
|
// 测试写入性能
|
|
|
|
BenchmarkWritePerformance(db, 100001); // 插入 100001 条数据
|
|
|
|
|
|
|
|
// 测试二级索引对查询性能的提升
|
|
|
|
BenchmarkFieldQueryWithIndex(db); |
|
|
|
|
|
|
|
// 获取数据库大小
|
|
|
|
GetDatabaseSize(db); |
|
|
|
|
|
|
|
// 测试删除二级索引的开销
|
|
|
|
BenchmarkDeleteIndex(db, "name"); |
|
|
|
|
|
|
|
// 关闭数据库
|
|
|
|
delete db; |
|
|
|
|
|
|
|
std::cout << "Benchmark tests completed." << std::endl; |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |