造轮子工程 · 第 8 章 造数据库 章节摘要:数据库是「系统软件」里最实用、也最让人敬畏的一个——我们天天用 MySQL/PostgreSQL/Redis,却很少想过它们内部是怎么运转的。本章要带你从零造一个迷你数据库,揭开它的神秘面纱。一个数据库要回答四个根本问题:数据存在哪里(页式存储)、怎么快速查到(B+树索引)、怎么保证不丢数据(预写日志 WAL 与崩溃恢复)、怎么让多条操作作为一个整体成功或失败(事务与隔离)。本章导读这四块:页式存储(把磁盘按固定大小的页管理)、B+树索引(高扇出平衡树,数据库索引的事实标准)、预写日志(先记后做,崩溃可回放恢复)、事务(ACID 的工程实现,尤其原子性与持久性)。我们还会简述查询解析(把 SQL 翻译成执行计划)。
章节摘要:数据库是「系统软件」里最实用、也最让人敬畏的一个——我们天天用 MySQL/PostgreSQL/Redis,却很少想过它们内部是怎么运转的。本章要带你从零造一个迷你数据库,揭开它的神秘面纱。一个数据库要回答四个根本问题:数据存在哪里(页式存储)、怎么快速查到(B+树索引)、怎么保证不丢数据(预写日志 WAL 与崩溃恢复)、怎么让多条操作作为一个整体成功或失败(事务与隔离)。本章导读这四块:页式存储(把磁盘按固定大小的页管理)、B+树索引(高扇出平衡树,数据库索引的事实标准)、预写日志(先记后做,崩溃可回放恢复)、事务(ACID 的工程实现,尤其原子性与持久性)。我们还会简述查询解析(把 SQL 翻译成执行计划)。读完本章,你理解了 SQLite 的核心机制——它就是这样一个「页式存储 + B+树 + WAL」的迷你数据库,而且它能在单文件里跑得飞快。
阅读完本章,你应当能够:
数据库的四大支柱:页式存储(怎么放)、B+树索引(怎么找)、WAL(怎么不丢)、事务(怎么算一个整体)。SQLite 就是这四块的精巧组合——单文件、嵌入式、却足够强大到支撑手机里所有 App 的数据。理解这四块,数据库的神秘感就消散了。
为什么不把每条记录存成一个文件(文件系统开销大、碎片严重),而是把整个数据库存成一个文件,内部按固定大小的「页」(如 4KB)切分管理。讲清页的分配、空闲页回收、页内如何紧凑存多条记录。呼应《Linux 命令》第 5 章(磁盘与块)。
为什么几乎所有数据库都用 B+树(非叶子节点只存键与子指针、叶子节点存数据并用链表串联)而非二叉树(太深)或哈希(不支持范围查询)。讲清 B+树的插入、分裂、查询,以及「聚簇索引」(数据存在 B+树叶子)的概念。
基于前两节,实现基础操作:插入一条记录(找到该去的页、写进去、必要时分裂、维护索引)、按主键查询(沿 B+树找叶子)、范围查询(用叶子的链表)。这一节让数据库「能存能取」。
数据库最怕「写一半断电」。WAL 的解法:先把要做的改动记进日志(顺序写,快),再改实际数据(随机写,慢)。崩溃后重放日志,要么把没做完的做完,要么把没提交的撤销。这是「持久性」的工程实现。
事务保证一组操作「全做或全不做」。重点讲原子性(用 WAL 的回滚段实现)、持久性(提交时强制刷日志)、隔离性(简述锁与 MVCC 多版本并发控制的思想,深度展开留给进阶书)、一致性(应用层约束 + 前三者共同保证)。
简述链路:SQL 文本 → 词法分析(参考第 9 章编译器)→ 语法分析(参考第 9 章)→ 查询优化器(选全表扫描还是索引)→ 执行。本节不深做,只让你建立「SQL 不是魔法,它也是被解析与执行的」的认知。
SQLite 是「迷你数据库」的典范:单文件、嵌入式、零配置、跨平台。讲清它为什么能用单文件支撑手机/浏览器里所有数据——页式存储 + B+树 + WAL 的精巧组合。你的迷你数据库可以照着这个思路收尾。
本章遵循「存储 → 索引 → 操作 → 可靠性 → 解析 → 综合」的递进路径,前两节是「怎么存与怎么找」,中间两节是「怎么用与怎么可靠」,后两节是「查询接口与综合」:
页式存储 (01) ── 数据怎么放 │ ▼ B+树索引 (02) ── 数据怎么找 │ ▼ 插入与查询 (03) ── 能存能取 │ ▼ WAL (04) ── 怎么不丢数据 │ ▼ 事务 ACID (05) ── 怎么算一个整体 │ ▼ 查询解析 (06) ── SQL 怎么变成执行 │ ▼ SQLite 哲学 (07) ── 全章综合:单文件数据库 │ ▼ 第 9 章:登顶——造操作系统与编译器
01-02 是地基(存储与索引,决定了数据库的天花板);03 是基本可用;04-05 是「可靠性」,这是数据库区别于普通文件的根本;06 是「易用性」(SQL 接口);07 是综合。建议你的迷你数据库分阶段:先做到 03(能存能取),再加 04-05(可靠),最后了解 06-07。
前置知识:
本章为后续章节奠定的基础: