编程与开发 · 第 6 期

自己写个数据库,心脏长什么样

B+树与 WAL · storage engine essentials

数据库的心脏是两样:B+树存数据(O(log n) 查找,磁盘友好),WAL防丢(先写日志再改数据,崩溃能恢复)。理解这两个,你就懂了为什么数据库能既快又不丢——不是魔法,是这两个数据结构撑起来的。
⏱ 约 12 分钟 🎯 想懂数据库内部的人 📦 源:build-your-own-x §8

01一个反共识:快和不丢,靠的是结构不是魔法

数据库"亿级数据秒查 + 断电不丢"听起来像魔法,其实是两个数据结构的功劳。

这两个加起来,就是存储引擎的骨架。SQLite、Postgres、MySQL 的 InnoDB,底层都是这套。不是魔法,是 B+树 + WAL。

快靠 B+树,
不丢靠 WAL。
灏天文库 · 编程与开发 P.18

02B+树插入演示:看节点怎么分裂

下面是一棵阶数=3(每节点最多 3 个 key)的 B+树。点"插入下一个",看节点满了怎么分裂成两个。

🌲 B+树插入演示
逐步插入 10,20,5,15,30,25,看节点分裂。
← 点"插入下一个"开始

03WAL:先写日志,再改数据

WAL 的规则简单到一句话:改数据前,先把这次改动写进日志并落盘。

  1. 要改 key=10 的值为 "new"。
  2. 先把"把 key=10 改成 new"这条记录写进 WAL 日志文件,fsync 落盘。
  3. 日志落盘成功后,才去改真正的 B+树数据页(这一步可以不立即落盘)。
  4. 崩溃了?重启时重放 WAL:把日志里记的改动重新做一遍,数据页恢复到崩溃前。

关键在第 2 步的"先落盘"——日志落盘了,即使数据页没落盘,重放日志也能补回。如果日志没落盘就崩了,那这次改动本来就丢了,但不会出现"日志说改了、数据没改"的不一致。这就是 ACID 里 D(持久性)的保证。

先写日志落盘,
再改数据页。
灏天文库 · 编程与开发 P.19

04带走这套清单

✅ 数据库存储 6 条可执行规则

  1. B+树是骨架:排序+分层,O(log n) 查找,叶子串链表做范围查询。
  2. 节点大小对齐磁盘页:一个节点一页,减少 IO,这是 B+树快的根本。
  3. WAL 先写日志落盘:改数据前日志必须 fsync,否则崩溃会不一致。
  4. 崩溃靠重放恢复:重启重放 WAL,把没落盘的改动补回。
  5. 页是读写单位:数据按页(4~16KB)读写,不是按字节,对齐磁盘。
  6. 从零写一遍:B+树插入+分裂、WAL 追加重放,比看文档懂 10 倍。
数据库不是魔法,
是 B+树 + WAL。
灏天文库 · 编程与开发 P.20