一次进程内点查:sqlite3_prepare_v2(db, "SELECT … WHERE id=?", …),再循环
sqlite3_step(stmt),没有
socket、没有连接池线程、没有独立数据库守护进程。调用栈从应用代码直接进入解析/字节码(或复用已
prepare 的 VDBE 程序),再经 Pager 取页、B-Tree
定位到记录。同一条 SQL 若走
PostgreSQL,则至少多出协议编解码、backend
进程调度与共享缓冲池上的锁协作——那是服务器行存为网络并发付出的固定税。
SQLite 是怎么做到十亿行每秒的 已经从性能叙事拆过页面布局、WAL 与 Page Cache;PostgreSQL 内核 与 InnoDB 内核 讲清了服务器怎么做行存。中间仍缺一层:嵌入式约束如何塑造内核路径,以及后续 17 篇如何把路径钉死。本文是「SQLite 内核」系列第 1 篇,只做三件事:
- 画出进程内 HashMap、SQLite、DuckDB、RocksDB、PG/InnoDB 的生态位地图。
- 用官方架构文档钉住「单文件 · 单写者 · 页式 B-Tree · VDBE」四条约束,并交代学术谱系与开放问题。
- 给出与站内系列的分工,以及 17 篇阅读路线。
本文是「SQLite 内核」系列第 1 篇(共 17 篇)。→ 系列目录
篇目 核心内容 第 1 篇 · 嵌入式行存全景 生态位、架构约束、系列路线 第 2 篇 · 单文件格式与页面头 Database header、page size、页类型 第 3 篇 · Pager 与 Page Cache 读改写契约与脏页
版本锚定:SQLite 3.45.x–3.46.x 官方文档(Architecture of SQLite、File Format For SQLite Databases、Write-Ahead Logging、File Locking And Concurrency In SQLite Version 3);源码以 amalgamation / 拆分树中的
pager.c、btree.c、vdbe*.c、wal.c为准。本文不复述 SQL 语言手册,也不展开 FTS / JSON 扩展。
一、一次点查:零 IPC 意味着什么
站内性能单篇用图对比了 MySQL/InnoDB 与 SQLite 的调用链深度。本系列直接复用该图,避免另绘一套口径不同的路径图:
图意:服务器路径要把请求送进独立进程并经过缓冲池协作;SQLite 路径把「连接」收成库内指针,热路径是函数调用。
1.1 三条可核对的工程后果
| 后果 | 机制含义 | 本系列落点 |
|---|---|---|
| 没有网络协议栈 | 无握手、无编解码、无连接线程池 | 第 5–6 篇:prepare/step |
| 没有跨进程共享缓冲池 | Page Cache 在本连接/本进程语义下工作;多进程靠 OS 文件锁协调 | 第 3、9 篇 |
| 写者数量有硬边界 | 同一数据库文件同一时刻通常只有一个写者(锁状态机保证) | 第 9–10 篇 |
官方 Architecture of SQLite 把 SQLite 描述为嵌入到应用进程中的库,而不是独立服务器。这不是营销口号:它直接删掉了「服务端进程模型」这一整层,换来延迟与部署简单性,也换来不能把 PG 的并发心智模型原样搬过来。
1.2 生态位:五格对照
flowchart TB
subgraph inproc ["In-process"]
HM["Language HashMap"]
SQL["SQLite<br/>SQL + B-Tree pages"]
DUCK["DuckDB<br/>analytical embed"]
RK["RocksDB<br/>LSM KV embed"]
end
subgraph server ["Client or server"]
PG["PostgreSQL / InnoDB<br/>multi-process row store"]
end
HM -->|"need SQL / durability"| SQL
SQL -.->|"heavy analytics"| DUCK
SQL -.->|"raw KV no SQL"| RK
SQL -->|"need multi-writer network"| PG
| 形态 | 接口 | 存储范式 | 典型约束 | 站内入口 |
|---|---|---|---|---|
| 语言内 Map | put/get |
堆对象 | 无跨进程、无 SQL | architecture/17 |
| SQLite | SQL / C API | 页式 B-Tree 单文件 | 单写者、嵌入式 | 本系列 |
| DuckDB | SQL | 列存 / 向量化 | 分析为主 | columnar-engine 边界 |
| RocksDB | KV API | LSM | 无 SQL 引擎 | rocksdb |
| PG / InnoDB | SQL + 网络 | 行存 + 服务器缓冲池 | 多写者、运维面大 | postgresql-kernel、mysql-innodb |
一句话:SQLite 占住的是「需要 SQL 与事务语义、但不想(或不能)跑独立数据库进程」的那一格——手机本地库、桌面应用、边缘设备、许多测试夹具与小型服务内嵌状态。
二、四条架构约束(后续章节的坐标系)
官方架构与 file format 文档反复出现的约束,可收成四条。本系列每一篇都应能回指其中至少一条。
2.1 单文件(可 cp
的数据库)
主库是一个普通文件(加上 journal 或
-wal/-shm 附属文件)。File
Format For SQLite Databases 规定了页大小、页类型与
B-Tree
在页内的布局。运维上的好处是备份与拷贝心智简单;代价是「库」与「文件生命周期」绑死——损坏、部分写、错误的热拷贝都会直接打在文件格式上(第
14–15 篇)。
2.2 单写者(锁状态机,不是「完全单线程」)
File Locking And Concurrency 定义锁阶梯:多个读者可持 SHARED;写路径升到 RESERVED / PENDING / EXCLUSIVE。「单写者」指同一数据库文件上的写互斥,不是「整个进程只能跑一个线程」。 多线程多连接可以并存,但写锁仍按文件粒度串行化写事务。第 9–10 篇展开;本篇只钉住:并发模型与 PG 行级锁不是同一物种。
2.3 页式 B-Tree(不是 LSM)
表与索引落在 B-Tree 页上(Bayer & McCreight, 1972 奠基;SQLite file format 给出工程字节布局)。这与 RocksDB 的 LSM(O’Neil et al., 1996)分叉:随机点查与短事务通常站在页式索引一侧;高吞吐顺序写与压缩策略站在 LSM 一侧。本系列不写跨范式吞吐排名,只在第 4、17 篇谈职责边界。
FoundationDB 早期 Storage 引擎曾借用 SQLite 派生的 B-Tree(见 foundationdb/12 Redwood)——那是分布式 KV 对页式引擎的取用史,不是本系列要重写的 SQLite SQL 层。
2.4 VDBE(SQL 编译成字节码再执行)
SQL
文本不在热路径上反复「解释执行」:sqlite3_prepare_v2
生成 VDBE 程序,sqlite3_step 推进虚拟机。官方
The VDBE 与 Architecture
把这层定位为可移植执行引擎。第 5–6
篇拆字节码与编译管线;本篇只强调:嵌入式并不等于「没有执行引擎」——它把执行引擎链进了应用进程。
flowchart LR
sql["SQL text"] --> prep["prepare_v2"]
prep --> vdbe["VDBE program"]
vdbe --> step["sqlite3_step loop"]
step --> pager["Pager"]
pager --> btree["B-Tree pages"]
btree --> file["Database file"]
step -.->|"writes"| journal["Journal or WAL"]
journal --> file
三、与站内系列的分工
| 话题 | 已有内容 | 本系列怎么用 |
|---|---|---|
| 为何延迟低、页面如何布局 | sqlite-billion-rows | 回链性能叙事与 SVG;不复述 speedtest/1BRC 数字为新测 |
| 服务器行存:进程、MVCC、WAL | postgresql-kernel、mysql-innodb | 第 16 篇机制对照;第 17 篇选型 |
| LSM 嵌入 KV | rocksdb | 第 4、17 篇边界:无 SQL / 写放大模型不同 |
| 列存分析嵌入 | columnar-engine | 第 17 篇 DuckDB 边界句 |
| 隔离级别概念 | mvcc | 第 10 篇引用 Berenson,不重写 PG CLOG |
| FDB 借用 B-Tree | foundationdb/12 | 第 4 篇一句历史回链 |
一句话:性能单篇回答「约束如何换速度」;PG/InnoDB 回答「服务器如何换并发」;本系列回答「嵌入式行存内核路径如何组织」。
常见误解
「SQLite 没有并发。」
多读者可并行;WAL 模式下读者与写者可更好重叠(官方 WAL 文档)。没有的是「多个写者同时改同一库文件」的默认模型,不是零并发。「SQLite 只是玩具 / 不能上生产。」
嵌入式生产面极广(移动 OS、浏览器、桌面应用、设备固件)。「能否生产」取决于工作负载是否匹配单写者与单机文件语义,不是玩具标签。Gaffney et al.(PVLDB 2022)从工程与分析负载两侧讨论其现状与瓶颈,本系列第 17 篇收选型,不在此用营销句替代。「SQLite 的 WAL 等于 PostgreSQL 的 WAL。」
名字相同,语义不同:SQLite WAL 是单文件库上的写前日志与 checkpoint 协议;PG WAL 服务服务器集群的崩溃恢复与复制。第 8、16 篇对照,禁止把运维经验直接平移。「嵌入 RocksDB 就能替代 SQLite。」
RocksDB 提供持久 KV 与迭代器,不提供 SQL、优化器与表约束。需要声明式查询与事务 SQL 时,缺的是引擎层,不是「再快一点的 Map」。
四、学术谱系、工程间隙与开放问题
4.1 谱系(奠基 → 工程定义 → 近期讨论)
| 阶段 | 代表 work | 与本系列关系 |
|---|---|---|
| 有序索引范式 | Bayer & McCreight, Organization and Maintenance of Large Ordered Indexes, Acta Informatica, 1972 | 第 4 篇 B-Tree 的问题定义锚点 |
| 日志结构写优化分叉 | O’Neil et al., The Log-Structured Merge-Tree, Acta Informatica, 1996 | 与 RocksDB 对照轴;本系列站在页式一侧 |
| 隔离级别词汇 | Berenson et al., A Critique of ANSI SQL Isolation Levels, SIGMOD 1995 | 第 10 篇事务/隔离用语;链 mvcc |
| 工程规范(A 级) | SQLite File Format / Locking / WAL / Architecture | 第 2–10 篇机制正文的直接来源 |
| 近期系统讨论 | Gaffney, Prammer, Brasfield, Hipp, Kennedy, Patel. SQLite: Past, Present, and Future. PVLDB 15(12), 2022. DOI: 10.14778/3554821.3554842 | 嵌入式 SQL 在分析负载上的瓶颈与演进;第 1、17 篇引用其问题框架,不把论文内实验数字冒充本站实测 |
4.2 工程间隙
论文与官方文档描述的是可移植 C 库在 POSIX/Windows 文件语义上的行为;生产中还叠了:
- 应用进程的崩溃域(库与宿主同生共死);
- 移动 OS 的后台杀进程与闪存特性;
- 容器只读根文件系统与卷权限;
- 多进程打开同一文件时的锁实现差异(NFS 等非推荐场景)。
本系列默认 本地 POSIX 文件系统上的推荐部署;非常规文件系统只在排障/选型篇点边界,不假装处处等价。
4.3 开放问题(有文献线索,本系列不关闭)
单写者是否应让位于页级锁?
官方长期选择文件级写互斥以换实现简单与损坏面可控;细粒度锁会靠近服务器引擎复杂度。争论存在于社区与扩展方案中,本系列按官方主线写,第 9–10 篇标注边界。WAL 默认化之后,checkpoint 与读放大如何治理?
WAL 改善读写重叠,但 checkpoint 策略与-wal增长是运维面(第 8 篇)。无本站新测时,只给机制与官方旋钮,不给「最佳 PRAGMA 配方」。嵌入式 SQL 与分析负载的分工。
Gaffney et al.(PVLDB 2022)讨论 SQLite 在分析场景上的瓶颈与优化方向;DuckDB 等列存嵌入式从另一侧切入。第 17 篇给选型决策树,不宣称其中一方将统一嵌入式 SQL。
五、17 篇阅读地图
flowchart TD
A["01 Overview"] --> B["02 Format"]
B --> C["03 Pager"]
C --> D["04 B-Tree"]
D --> E["05 VDBE"]
E --> F["06 Compile"]
C --> G["07 Journal"]
G --> H["08 WAL"]
H --> I["09 Locks"]
I --> J["10 Txn"]
F --> K["11 Planner"]
D --> L["12 Indexes"]
J --> M["13 ATTACH"]
H --> N["14 Integrity"]
N --> O["15 Backup"]
J --> P["16 PG/InnoDB"]
P --> Q["17 Selection"]
L --> Q
O --> Q
| 路径 | 建议篇目 | 目标 |
|---|---|---|
| 必读核心 | 1 → 2 → 3 → 4 → 5 → 8 → 9 → 17 | 建立坐标系并会选型 |
| 持久化深读 | 7 → 8 → 9 → 10 → 14 → 15 | 写路径、锁、损坏与备份 |
| 从 PG 过来 | 1 → 16 → 8 → 9 → 17 | 先对照再下沉 |
| 完整通读 | 1 … 17 | 系统掌握 |
系列规划与实验台账见 PLAN.md;实验脚本放在 reproduce/。
六、小结
三句话小结
- SQLite 占住「需要 SQL/事务、但嵌入应用进程」的生态位:单文件、页式 B-Tree、VDBE 执行、文件级写互斥——与 PG/InnoDB 服务器行存、RocksDB LSM、DuckDB 分析嵌入式分工清晰。
- 零 IPC 换来的是调用链变短,不是「没有引擎」;后续篇章按 Pager → B-Tree → VDBE → Journal/WAL → 锁 → 计划 → 选型展开。
- 学术锚点是 Bayer & McCreight(B-Tree)、官方 file format/locking/WAL(工程定义)、Berenson(隔离词汇)、O’Neil LSM(对照分叉)、Gaffney et al. PVLDB 2022(近期嵌入式 SQL 讨论);单写者与分析负载分工仍是开放问题。
常见误解(收束)
上文第三节四条已覆盖「无并发 / 玩具 / WAL 等同 PG / RocksDB 可替代」;读完本篇后,把 SQLite 当成「小 PostgreSQL」或「带 SQL 的 HashMap」都会在第 8–10、16–17 篇被机制打脸。
参考资料
规范与官方文档(A 级)
- SQLite Documentation, Architecture of SQLite(sqlite.org)。
- SQLite Documentation, File Format For SQLite Databases(sqlite.org)。
- SQLite Documentation, Write-Ahead Logging;File Locking And Concurrency In SQLite Version 3;Atomic Commit In SQLite。
- SQLite Documentation, The Virtual Database Engine (VDBE);Query Planning。
论文(A 级)
- Bayer, R. & McCreight, E. Organization and Maintenance of Large Ordered Indexes. Acta Informatica, 1972。
- O’Neil, P., Cheng, E., Gawlick, D. & O’Neil, E. The Log-Structured Merge-Tree (LSM-Tree). Acta Informatica, 1996。
- Berenson, H., Bernstein, P., Gray, J., Melton, J., O’Neil, E. & O’Neil, P. A Critique of ANSI SQL Isolation Levels. SIGMOD 1995。
- Gaffney, K. P., Prammer, M., Brasfield, L., Hipp, D. R., Kennedy, D. & Patel, J. M. SQLite: Past, Present, and Future. PVLDB 15(12): 3535–3547, 2022. DOI: 10.14778/3554821.3554842。
站内
- SQLite 是怎么做到十亿行每秒的(性能叙事与路径对比图)。
- PostgreSQL 内核、MySQL InnoDB 内核、RocksDB 内核、列存引擎。
- 本系列 index、PLAN.md。
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【SQLite 内核】单文件 · Pager · B-Tree · VDBE · WAL · 锁
补齐嵌入式行存内核层:从单文件格式、Pager/B-Tree、VDBE 到 Rollback Journal/WAL、锁状态机与计划器,并以 PG/InnoDB、DuckDB、RocksDB 对照收束;承接 sqlite-billion-rows 性能叙事。
【SQLite 内核】单文件格式与页面头
拆解 SQLite 单文件格式:100 字节 database header 与 B-Tree 页面头的逐字段布局,用本机 3.53.2 CLI 实测 hexdump 核对 magic、page size、页类型标志,并钉住 file format 官方规范与 Bayer/McCreight 谱系。
【SQLite 内核】Pager 与 Page Cache
拆解 Pager 作为 B-Tree 与操作系统文件之间的契约层:page cache 命中/未命中路径、脏页生命周期与提交前的可回滚保证,并与 PG shared_buffers、InnoDB Buffer Pool 的跨进程共享模型对照。
【SQLite 内核】B-Tree 遍历与分裂:表 B-Tree、索引 B-Tree 与 cell 布局
钉住 SQLite table b-tree 与 index b-tree 的字节布局差异、cell pointer array 如何做到逻辑有序物理可乱序、overflow 阈值与 balance() 分裂/合并触发条件;源码以 btree.c 函数签名为准,学术锚点是 Bayer & McCreight 1972。