打造先进的内存KV数据库-3 最终选择-C & B-Tree

在对比了Tire树、B+树和B树索引后,发现B树索引在性能上最优,C语言实现的B树索引在15w数据查询中达到约60ns/条,15M数据查询不超过100ns/条。然而,通过cgo调用C代码会带来显著性能损失。因此,决定使用原生C语言完成后续的数据库进程。
摘要由CSDN通过智能技术生成

多种索引与语言

我尝试了tire树索引 B+树索引 B树索引,发现还是B树索引最快,另外使用C写了完善的B树索引,但是我发现使用cgo调用的时候,会有500%左右的性能损失,tire树大概比B树慢2倍,所以还是选择使用原生C来写完后续的进程。

索引代码实现

//BTree.h
//实现对order序(阶)的B-TREE结构基本操作的封装。
//查找:search,插入:insert,删除:remove。
//创建:create,销毁:destory,打印:print。
#ifndef BTREE_H
#define BTREE_H

#ifdef __cplusplus
extern "C" {
#endif

* 定义m序(阶)B 树的最小度数BTree_D=ceil(m)*/
/// 在这里定义每个节点中关键字的最大数目为:2 * BTree_D - 1,即序(阶):2 * BTree_D.
#define L2_CACHE      (256 * 1024) //CPU L2缓存大小
#define BTree_D        (L2_CACHE / 32)
#define ORDER        (BTree_D * 2) //定义为4阶B-tree,2-3-4树。最简单为3阶B-tree,2-3树。
//#define ORDER        (BTree_T * 2-1)  //最简单为3阶B-tree,2-3树。
#define true 1
#define false 0

    typedef int bool;
    typedef unsigned long long KeyType;
    typedef struct BTNode{
        int keynum;                        /// 结点中关键字的个数,keynum <= BTree_N
        KeyType key[ORDER-1];                /// 关键字向量为key[0..keynum - 1]
        struct BTNode* child[ORDER];        /// 孩子指针向量为child[0..keynum]
        const void* pRecord[ORDER-1];               /// 指向储存位置的指针
        bool isLeaf;                    /// 是否是叶子节点的标志
    }BTNode;

    typedef BTNode* BTree;  ///定义BTree

    ///给定数据集data,创建BTree。
    void BTree_create(BTree* tree, const KeyType* data, const void** records, int length);

    ///销毁BTree,释放内存空间。
    void BTree_destroy(BTree* tree);

    ///在BTree中插入关键字key。
    void BTree_insert(BTree* tree, KeyType key,const void* pRecode);

    ///在BTree中移除关键字key。
    void BTree_remove(BTree* tree, KeyType key);

    ///深度遍历BTree打印各层结点信息。
    void BTree_print(const BTree tree, int layer);

    /// 在BTree中查找关键字 key,
    /// 成功时返回找到的节点的地址及 key 在其中的位置 *pos
    /// 失败时返回 NULL 及查找失败时扫描到的节点位置 *pos
    BTNode* BTree_search(const BTree tree, KeyType key, int* pos);

#ifdef __cplusplus
}
#endif

#endif
//BTree.c
//实现对order序(阶)的B-TREE结构基本操作的封装。
//查找:search,插入:insert,删除:remove。
//创建:create,销毁:destory,打印:print。
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "btree.h"
#define RELEASE_VERSION 1
//#define max(a, b) (((a) > (b)) ? (a) : (b))
#define cmp(a, b) ( ( ((a)-(b)) >= (0) ) ? (1) : (0) ) //比较a,b大小



// 模拟向磁盘写入节点
void disk_write(BTNode* node)
{
//打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。
    printf("向磁盘写入节点");
    for(int i=0;i<ORDER-1;i++){
        printf("%llu",node->key[i]);
    }
    printf("\n");
}

// 模拟从磁盘读取节点
void disk_read(BTNode** node)
{
//打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。
    printf("向磁盘读取节点");
    for(int i=0;i<ORDER-1;i++){
        printf("%llu",(*node)->key[i]);
    }
    printf("\n");
}

// 按层次打印 Bvoid BTree_print(const BTree tree, int layer)
{
    int i;
    BTNode* node = tree;

    if (node) {
        printf("第 %d 层, %d node : ", layer, node->keynum);

        //打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。
        for (i = 0; i < ORDER-1; ++i) {
        //for (i = 0; i < node->keynum; ++i) {
            if(node->key[i] == 0)continue;
            printf("%llu ", node->key[i]);
        }

        printf("\n");

        ++layer;
        for (i = 0 ; i <= node->keynum; i++) {
            if (node->child[i]) {
                BTree_print(node->child[i], layer);
            }
        }
    }
    else {
        printf("树为空。\n");
    }
}

// 结点node内对关键字进行二分查找。
int binarySearch(BTNode* node, int low, int high, KeyType Fkey, bool* success)
{
    int mid;
    while (low<=high)
    {
        mid = (high+low) >> 1;
        if (Fkey<node->key[mid])
        {
            high = mid-1;
        }
        if (Fkey>node->key[mid])
        {
            low = mid+1;
        }
        if (Fkey==node->key[mid])
        {
            *success = true;
            return mid;//返回下标。
        }
    }
    *success = false;
    return low;//未找到返回-1.
}

//insert
/*************************************
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值