第 1 章

架构总览

难度:入门 | 免费章节

你每天都在用 MySQL、PostgreSQL——但你有没有想过,当你敲下一条 SELECT * FROM users 时,数据库内部到底发生了什么?本课程带你亲手从零构建一个能运行 SQL 的数据库,揭开这个黑盒。

1. 你将构建什么

学完本课程,你将拥有一个自己写的 SQL 数据库——它能理解并执行真正的 SQL 语句:

-- 创建表
CREATE TABLE users (id INT, name VARCHAR NOT NULL, age INT DEFAULT 0);

-- 插入数据
INSERT INTO users VALUES (1, 'Alice', 28);
INSERT INTO users (id, name) VALUES (2, 'Bob');

-- 查询数据
SELECT * FROM users;

你的数据库将包含一个 SQL 数据库的核心模块

SQL 解析器

Lexer + Parser,将 SQL 文本变成结构化的语法树

查询计划器

分析语法树,生成执行计划

执行引擎

按照计划读取、处理、返回数据

存储引擎

从内存 KV 到磁盘持久化

事务 (MVCC)

快照隔离,并发安全

而且,你会用 Go、Rust、Java、C++ 四种语言同步实现——同一个架构,四种视角,选你最擅长的语言入手,或者用不熟悉的语言挑战自己。

麻雀虽小,五脏俱全。我们不会试图复制 PostgreSQL 的百万行代码,但你的数据库将覆盖从 SQL 解析到数据存储的完整链路。理解了这个核心架构,再去阅读任何生产级数据库的源码都会事半功倍。

与真实数据库的对比

你日常使用的 MySQL、PostgreSQL、SQLite 虽然功能丰富、代码量巨大(PostgreSQL 超过 100 万行 C 代码),但它们的核心架构是相通的——都遵循"SQL 前端 → 执行引擎 → 存储引擎"的分层模式:

层次职责本课程实现
SQL 前端解析 SQL 文本,生成执行计划Lexer + Parser + Planner
执行引擎按照执行计划处理数据Executor(Volcano 迭代器模型)
事务管理并发控制、ACID 保证MVCC 快照隔离
存储引擎数据在磁盘上的组织和读写内存 KV → 磁盘持久化

几个主流数据库的架构特点:

从简单到复杂
生产级数据库在每个层次上都做了大量优化——查询重写、代价估算、Buffer Pool、WAL、并发索引……这些复杂性是几十年工程积累的结果。本课程的策略是先用最简单的方式实现每个层次,让你理解整体架构,然后再逐步深入。你不需要一开始就理解 B+ Tree 或 WAL 恢复机制,只需要知道每个模块的角色和边界。

2. SQL 执行全景

当你敲下一条 SQL,数据库内部会按照这条流水线依次处理:

SQL 文本 Lexer 词法分析 Token 流 Parser 语法分析 AST Planner 查询计划 Executor 执行引擎 Storage Engine 存储引擎

五个模块,各司其职:

  1. Lexer(词法分析):将 SQL 字符串拆分为 Token 流
  2. Parser(语法分析):将 Token 流组织成 AST(抽象语法树)
  3. Planner(查询计划):分析 AST,生成执行计划
  4. Executor(执行引擎):按照执行计划获取和处理数据
  5. Storage Engine(存储引擎):负责数据的读写和持久化

这条流水线就是 MySQL、PostgreSQL、SQLite 等所有 SQL 数据库共享的核心架构。

本课程的数据库架构

我们在课程中实现的 SQL 数据库,基本涵盖了上述所有核心组件。下面是整体架构图:

CLIENT SQL SERVER SQL Engine Parser AST Planner Optimizer Plan Node Executor Storage Engine MVCC KV Storage Memory Disk CRUD

整体分为两大部分:

接下来我们逐层拆解每个模块。

3. 逐层拆解

Lexer —— 把 SQL 拆成"词"

Lexer 是流水线的起点,逐字符扫描 SQL 字符串,将其切分为 Token:

SELECT id FROM users WHERE age > 18
  ↓
[Keyword(SELECT), Ident("id"), Keyword(FROM), Ident("users"), Keyword(WHERE), Ident("age"), GreaterThan, Number("18")]

每个 Token 包含类型(关键字、标识符、数字、符号)和(原始文本)。Lexer 不理解语义——SELECT SELECT FROM FROM 对它来说完全合法。

Parser —— 构建语法树

Parser 接收 Token 流,组织成一棵 AST(抽象语法树),用树状结构表达 SQL 的逻辑含义:

SELECT Statement Columns FROM WHERE id users GreaterThan (>) age 18

AST 把 SQL 的结构信息完整保留下来——查哪些列、从哪张表、过滤条件是什么——后续模块只需要遍历这棵树。

Planner —— 生成执行计划

Planner 拿到 AST 后,生成一份执行计划(Plan)。执行计划通常以树状结构的形式表示,其中包含了执行查询所需的各种操作,如索引扫描、表扫描、连接操作等。

Optimizer —— 选择最优路径

Optimizer 负责根据执行计划生成的各种执行路径,选择最优的执行方案。它的目标是在保证查询结果正确性的前提下,尽可能降低查询的成本——包括 CPU、内存和 IO 等资源的消耗。

为了达到这个目标,Optimizer 会考虑多种因素:

Planner 与 Optimizer 的关系
在生产级数据库(如 PostgreSQL、MySQL)中,Planner 和 Optimizer 是极其复杂的模块。本课程会先实现一个简化版的 Planner,聚焦于基本的执行计划生成;后续章节再加入 Optimizer,支持简单的查询优化。理解了基础原理后,你可以进一步阅读相关论文深入学习。

Executor —— 真正干活的人

Executor(执行器)负责具体去执行执行计划中的各个节点。一般的执行器模型采用推(Push)或者拉(Pull)的方式。

最常见的是基于 Pull 的 Volcano 模型(火山模型),会从最顶层的节点开始执行,循环拉取下层节点的结果,直到完全执行并返回。每个操作符实现一个 Next() 方法,像流水线一样串联:

Transaction —— 事务保障

事务是数据库系统中的重要概念,它是一系列数据库操作的逻辑单元,要么全部执行成功,要么全部执行失败。事务管理组件负责确保事务的 ACID 属性:

属性含义
Atomicity(原子性)事务中的操作要么全部成功,要么全部回滚
Consistency(一致性)事务前后数据保持一致状态
Isolation(隔离性)并发事务之间互不干扰
Durability(持久性)事务提交后数据不丢失

本课程会实现基于 MVCC(多版本并发控制)的快照隔离事务,在多版本的基础上,让多个事务可以并发读写而不互相阻塞。

Storage Engine —— 数据的家

存储引擎是数据库内核中负责管理数据存储和检索的组件,它负责将数据存储到物理存储介质中,并提供高效的数据访问接口。一个典型的存储引擎包含以下关键组件:

组件职责
Page数据在磁盘上的基本读写单位(通常 4KB 或 8KB)
Buffer Pool内存中的页面缓存,减少磁盘 I/O
WALWrite-Ahead Log,先写日志再写数据,保证崩溃恢复
索引加速查询的辅助数据结构

本课程的存储引擎采用 KV 接口设计,上层是 MVCC 事务层,下层支持内存和磁盘两种实现。先用内存 KV 存储快速跑通整个架构,后续再实现基于磁盘的持久化存储引擎。

4. 一条 SQL 的完整旅程

现在把所有模块串起来。当你输入 SELECT id FROM users WHERE age > 18; 时:

  1. Lexer 扫描字符串,输出 Token 流:[SELECT, id, FROM, users, WHERE, age, >, 18]
  2. Parser 消费 Token 流,构建一棵以 SELECT 为根的 AST
  3. Planner 分析 AST,生成执行计划:扫描 users 表 → 过滤 age > 18 → 投影 id
  4. Executor 按照计划,调用 Storage Engine 逐行读取数据
  5. Storage Engine 返回数据,Executor 将最终结果交给用户

每个模块只负责一件事,通过清晰的接口传递数据。这种分层架构带来三个好处:

5. 课程的构建策略

本课程采用"先跑通、再完善"的策略:

阶段章节内容
搭骨架第 1 ~ 9 章用最简单的 SQL(CREATE TABLE / INSERT / SELECT)+ 内存存储,搭建从 Lexer 到 Storage Engine 的完整链路
加血肉第 10 章起磁盘持久化存储引擎、事务(MVCC)、更多 SQL 语法……

这样你在第 9 章就能看到一条 SQL 从输入到结果返回的完整过程——而不是写了一堆代码却看不到效果。每一章都在上一章的基础上增量开发,你始终有一个能运行的系统

为什么先用内存存储?
磁盘存储引擎涉及大量底层细节(页面管理、缓冲池、日志恢复……),如果一上来就实现,你可能写了几千行代码还看不到一条 SQL 跑起来。先用内存 KV 存储搭好整个架构,你就能快速验证 SQL 解析、计划生成、执行引擎等模块是否正确。有了这个能运行的骨架,再替换存储引擎就是"换零件",而不是"从头来"。

本章小结

  1. 目标:从零构建一个能运行 CREATE TABLE / INSERT / SELECT 的 SQL 数据库,Go / Rust / Java / C++ 四语言同步实现。
  2. 核心架构:SQL Engine(Parser → Planner → Optimizer → Executor)+ Storage Engine(MVCC → KV Storage)。
  3. SQL 执行流水线:SQL 文本 → Lexer(Token 流)→ Parser(AST)→ Planner → Optimizer → Executor → Storage Engine。
  4. 事务保障:基于 MVCC 的快照隔离,保证 ACID 属性。
  5. 构建策略:前 9 章用最简单的 SQL + 内存存储搭骨架,第 10 章起加入磁盘持久化、事务等进阶特性。

下一章我们将搭建开发环境,为动手写代码做好准备。