数据库引擎背后的8种核心数据结构

  |   0 评论   |   69 浏览

你的数据库选择什么索引,本质上是在问:你的应用是读多还是写多?

当我们谈论数据库性能优化时,往往会不自觉地想到"加个索引"这个万能答案。但你有没有想过:索引本身也需要数据结构来支撑?而选择什么样的数据结构,直接决定了你的数据库在高并发场景下的表现。

今天,我们来深入探讨支撑现代数据库系统的8种核心数据结构。


一、为什么没有"银弹"数据结构?

答案取决于你的使用场景:
- 数据存储位置:内存还是磁盘?
- 数据格式:数字、字符串、地理坐标…
- 读写模式:读多写少?写多读少?

这些因素共同决定了你应该选择什么样的索引格式。


二、8种核心数据结构全景图

Data Structures That Power Your Databases


三、内存索引:速度至上

1. Skiplist(跳表)

使用场景:内存索引
典型案例:Redis ZSET

跳表是什么?想象一下,你在地铁里找出口。如果只有一条通道(链表),你需要从头走到尾。但如果有"捷径"(多层索引),你就可以"跳"过很多节点,快速找到目标。

跳表通过多层链表结构,将查找时间从 O(n) 降低到 O(log n),同时保持插入删除的简单性。

为什么Redis选择跳表而不是平衡二叉树?
- 实现简单,不需要复杂的旋转操作
- 范围查询更高效(天然的有序链表)
- 内存访问模式更友好

2. Hash Index(哈希索引)

使用场景:内存索引
特点:最常见的内存索引实现

哈希索引 = 哈希表 = 最快的精确查询

O(1) 的查找效率让它成为精确匹配的首选。但代价是什么?
- 不支持范围查询:你不能查找"所有 age > 18 的用户"
- 哈希冲突:需要处理碰撞,影响性能
- 无序性:无法利用数据的局部性原理


四、磁盘索引:持久化的艺术

3. SSTable(Sorted String Table)

使用场景:磁盘索引
特点:不可变的数据结构,很少单独使用

SSTable 的核心思想:数据一旦写入,永不修改

这听起来很极端,但带来了巨大好处:
- 写操作极快:顺序写入磁盘,无需随机 I/O
- 读操作简单:数据有序,可以用二分查找
- 并发安全:不可变意味着没有锁竞争

但它也有致命弱点:无法高效更新。这就引出了下一个结构…

4. LSM Tree(Log-Structured Merge Tree)

使用场景:内存 + 磁盘
特点:高写入吞吐量

LSM Tree = Skiplist(内存) + SSTable(磁盘)

工作原理
1. 写入:数据先写入内存的 Skiplist(MemTable)
2. 刷新:内存满了,排序后写入磁盘成为 SSTable
3. 合并:后台定期合并多个 SSTable,减少文件数量

优势:将随机写转化为顺序写,写入性能极佳
劣势:读取可能需要查询多个 SSTable,磁盘压缩可能影响性能

HBase、Cassandra、RocksDB 都在使用 LSM Tree。

5. B-tree(B树)

使用场景:磁盘索引
特点:最流行的数据库索引实现

MySQL 的 InnoDB、PostgreSQL、MongoDB…几乎所有关系型数据库都在用 B-tree(或其变种 B+ tree)。

为什么 B-tree 适合磁盘?

磁盘 I/O 是昂贵的。B-tree 通过一个关键设计优化了这一点:每个节点可以存储多个 key

这意味着:
- 树的高度更低:一次磁盘 I/O 能读取更多数据
- 读写性能稳定:查询时间稳定在 O(log n)
- 范围查询友好:B+ tree 的叶子节点形成链表

LSM Tree vs B-tree
- 写密集型:选 LSM(时序数据、日志、消息队列)
- 读密集型:选 B-tree(传统 OLTP 业务)


五、专用索引:为特定场景而生

6. Inverted Index(倒排索引)

使用场景:文档搜索
典型案例:Lucene、Elasticsearch

你在 Google 搜索"数据库原理"时,它是怎么快速找到包含这两个词的文档的?

倒排索引的核心思想:从"文档→词语"翻转为"词语→文档"

文档1: "数据库原理很有趣"
文档2: "我喜欢学习数据库"

倒排索引:
"数据库" → [文档1, 文档2]
"原理" → [文档1]
"很有趣" → [文档1]

这使得全文搜索变得极其高效。

7. Suffix Tree(后缀树)

使用场景:字符串模式搜索
应用:字符串后缀匹配

想象一下,你需要在 10GB 的文本中找出所有包含"banana"的子串位置。

后缀树将字符串的所有后缀组织成一棵压缩的字典树,使得:
- 子串查找:O(m) 时间复杂度(m 为模式长度)
- 最长重复子串
- 最长公共子串

基因序列分析、文本压缩、生物信息学都在使用它。

8. R-tree

使用场景:多维空间搜索
应用:最近邻搜索、地理信息系统

“查找距离我 5km 内的所有咖啡店”

B-tree 只能处理一维数据(数字、字符串),但地理位置是二维的(经度、纬度)。

R-tree 将空间数据组织成层次化的边界矩形
- 每个节点用一个矩形包围其子节点
- 查询时只需判断矩形是否与搜索区域相交

PostGIS、MongoDB 的 2d 索引都在使用 R-tree 的变种。


六、如何选择适合你的数据结构?

场景 推荐数据结构 典型代表
精确查询(内存) Hash Index Redis Hash
有序集合(内存) Skiplist Redis ZSET
写密集型 LSM Tree HBase, RocksDB
读密集型 B-tree MySQL, PostgreSQL
全文搜索 Inverted Index Elasticsearch
字符串匹配 Suffix Tree 基因分析工具
地理位置查询 R-tree PostGIS

七、总结

数据库索引的世界里,没有"最好"的数据结构,只有"最适合"的。

理解这些底层结构,能帮助你:
1. 选择合适的数据库:为什么用 Elasticsearch 而不是 MySQL 做全文搜索?
2. 优化查询性能:为什么 GeoHash 查询在 MySQL 中很慢?
3. 设计更好的系统:时序数据为什么要用 LSM 结构?

下次当你遇到性能瓶颈时,不妨问问自己:我选对数据结构了吗?

善忘技术夹-公众号

评论

发表评论

validate