CppGuide社区 CppGuide社区
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
  • C++语言面试问题集锦
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • 🔥C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 🔥从零用C语言写一个Redis
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 🔥使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
  • C++语言面试问题集锦
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • 🔥C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 🔥从零用C语言写一个Redis
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 🔥使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
  • 使用Go从零开发一个数据库 说明
  • 1.文件与数据库
  • 2.索引
    • 2.1 键值存储与关系型数据库
    • 2.2 哈希表
    • 2.3 B树
    • 2.4 LSM树
      • 查询操作
      • 更新操作
      • 查询方面
      • 更新方面
  • 3.B树:原理
  • 4.B树:实践(第一部分)
  • 5.B树:实践(第二部分)
  • 6.持久化到磁盘
  • 7.空闲列表:重用页面
  • 8.行与列
  • 9.范围查询
  • 10.二级索引
  • 11.原子事务
  • 12.并发读写
  • 13.查询语言:解析器
  • 14.查询语言:执行
目录

2.索引

# 02. 索引

# 2.1 键值存储与关系型数据库

虽然关系型数据库支持多种类型的查询,但几乎所有查询都可以归结为三种磁盘操作类型:

  1. 扫描整个数据集(不使用索引)。
  2. 点查询:通过特定键查询索引。
  3. 范围查询:通过一个范围查询索引(索引是有序的)。

数据库索引主要用于范围查询和点查询,很容易看出,范围查询其实就是点查询的超集。如果提取数据库索引的功能,构建一个键值存储并不复杂。关键在于,数据库系统可以构建在键值存储之上。

在尝试构建关系型数据库之前,我们先构建一个键值存储,但首先让我们探讨一下有哪些可选方案。

# 2.2 哈希表

在设计通用的键值存储时,哈希表是首先被排除的选项。主要原因是排序——现实世界中的许多应用确实需要对数据进行排序和整理。

不过,在特定应用中使用哈希表是可行的。使用哈希表的另一个麻烦是调整大小的操作。简单的调整大小操作时间复杂度为O(n),会导致磁盘空间和输入输出(IO)突然增加。虽然可以逐步调整哈希表的大小,但这又增加了复杂性。

# 2.3 B树

平衡二叉树的查询和更新时间复杂度为O(log(n)),并且支持范围查询。B树大致是一种平衡的n叉树。为什么使用n叉树而不是二叉树呢?原因有以下几点:

  1. 空间开销更小。

二叉树中每个叶节点都通过父节点的指针访问,并且父节点可能还有自己的父节点。平均而言,每个叶节点需要1 - 2个指针。

相比之下,B树中一个叶节点的多个数据共享一个父节点。而且n叉树更矮,在指针上浪费的空间更少。 2. 在内存中速度更快。

由于现代CPU的内存缓存等因素,即使n叉树和二叉树的大O复杂度相同,n叉树的速度也可能更快。 3. 磁盘IO更少。 - B树更矮,这意味着磁盘寻道次数更少。 - 磁盘IO的最小大小通常是内存页的大小(可能是4K)。即使读取的数据量较小,操作系统也会填充整个4K页。如果我们充分利用4K页中的所有信息(通过选择至少一个页大小的节点),就能达到最佳效果。

在本专栏中,我们将使用B树。但B树并不是唯一的选择。

# 2.4 LSM树

即日志结构合并树(Log-structured merge-tree)。下面是对LSM树操作的概述:

# 查询操作

  1. LSM树包含多个级别的数据。
  2. 每个级别都是有序的,并被分割成多个文件。
  3. 点查询从最高级别开始,如果未找到键,则继续在下一级别搜索。
  4. 范围查询合并所有级别的结果,在合并时,更高级别的结果具有更高的优先级 。

# 更新操作

  1. 更新键时,首先将键插入到最高级别的文件中。
  2. 如果文件大小超过阈值,就将其与下一级别的文件合并。
  3. 文件大小阈值随着级别呈指数增长,这意味着数据量也呈指数增长。

下面分析其工作原理:

# 查询方面

  1. 每个级别都是有序的,可以通过二分查找找到键,范围查询就是顺序文件IO操作,效率较高。

# 更新方面

  1. 最高级别的文件较小,因此插入操作只需要少量的IO。
  2. 数据最终会合并到较低级别。合并操作是顺序IO,这是一个优势。
  3. 更高级别更频繁地触发合并,但合并的数据量也较小。
  4. 将一个文件合并到较低级别时,任何范围有交集的较低级别文件都会被合并结果(可能是多个文件)替换。由此可以看出,将级别分割成多个文件是为了减小合并的规模。
  5. 合并操作可以在后台进行。然而,较低级别的合并可能会突然导致较高的IO使用率,从而降低系统性能。

读者在读完本专栏后,可以尝试使用LSM树代替B树,并比较B树和LSM树的优缺点。

上次更新: 2025/04/16, 02:04:00
1.文件与数据库
3.B树:原理

← 1.文件与数据库 3.B树:原理→

最近更新
01
第二章 关键字static及其不同用法
03-27
02
第一章 auto与类型推导
03-27
03
C++语言面试问题集锦 目录与说明
03-27
更多文章>
Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式