第一章 认识 SQLite
1.1 SQLite 是什么 —— 一句话理解
SQLite = 一个嵌入在你的应用程序里的关系型数据库引擎。
和 MySQL、PostgreSQL 不同,SQLite 没有独立的服务器进程,它直接以 库(Library) 的形式链接到你的程序中。整个数据库就是磁盘上的一个文件,不需要安装、不需要配置、不需要启动服务——import sqlite3 就能用。
┌─────────────────────────────────────────┐
│ 你的应用程序 │
│ │
│ ┌───────────────────────────────┐ │
│ │ SQLite 引擎 │ │
│ │ (直接链接在进程内部) │ │
│ │ │ │
│ │ SQL 解析 → 虚拟机执行 │ │
│ │ → B-Tree 存储 → 文件 I/O │ │
│ └───────────┬───────────────────┘ │
│ │ │
└───────────────┼─────────────────────────┘
│
↓
┌──────────────┐
│ database.db │ ← 整个数据库就是一个文件
│ (磁盘文件) │
└──────────────┘它有多普及?看一组数据:
| 指标 | 数字 |
|---|---|
| 全球活跃部署量 | 超过 1 万亿个 |
| 你手机里有几个 SQLite 数据库 | 平均 数百个 |
| 内置 SQLite 的系统/软件 | Android、iOS、Chrome、Firefox、微信、Telegram…… |
| 代码量 | 约 15 万行 C 代码(含注释约 100 万行测试代码) |
一句话概括:SQLite 是世界上部署量最大的数据库引擎——不是之一。每一台智能手机、每一个浏览器、每一个操作系统里,都有它的身影。
1.2 SQLite 的设计哲学
SQLite 的创造者 D. Richard Hipp 为它确立了几个核心设计原则,理解这些原则能帮你判断什么时候该用它、什么时候不该用。
零配置(Zero-Configuration)
不需要 my.cnf、不需要 postgresql.conf、不需要设置用户名密码。打开文件就是打开数据库,关闭文件就结束了。
import sqlite3
# 这一行就创建了一个完整的关系型数据库
conn = sqlite3.connect("my_app.db")没有 DBA(数据库管理员),没有配置调优,做到了真正的开箱即用。
无服务器(Serverless)
传统数据库的架构是 客户端-服务器 模式:
传统数据库(MySQL / PostgreSQL):
┌────────┐ ┌────────────┐ ┌────────┐
│ 客户端 │ ──TCP──→ │ 数据库服务器 │ ──读写──→ │ 磁盘 │
│ (应用) │ ←─TCP── │ (独立进程) │ ←─读写── │ 文件 │
└────────┘ └────────────┘ └────────┘
SQLite:
┌──────────────────────┐ ┌────────┐
│ 应用程序 │ │ │
│ ┌──────────────┐ │ ──读写──→│ 磁盘 │
│ │ SQLite (库) │ │ ←─读写──│ 文件 │
│ └──────────────┘ │ │ │
└──────────────────────┘ └────────┘
少了一层网络通信,少了一个独立进程。SQLite 直接通过文件系统 API 读写磁盘,没有网络通信开销,没有进程间通信开销。
单文件(Single-File)
一个 SQLite 数据库 = 一个磁盘文件。这意味着:
- 备份:
cp database.db database_backup.db - 迁移:把文件复制到另一台机器就行
- 版本控制:可以和代码一起提交(小型数据库)
- 跨平台:同一个
.db文件可以在 Windows、macOS、Linux 之间无缝使用
自包含(Self-Contained)
SQLite 的所有功能都打包在一个 C 源文件(sqlite3.c,约 25 万行)里。没有外部依赖,不需要额外安装任何东西。这让它可以轻松嵌入到任何环境中——从嵌入式设备到航天飞机。
设计理念总结:SQLite 的目标不是替代 MySQL / PostgreSQL,而是替代
fopen()。它解决的核心问题是:让应用程序以 SQL 的方式管理本地数据,而不是自己去解析文本文件或二进制格式。
1.3 SQLite 能解决什么问题
SQLite 不是万能的,但在以下场景中它是最佳选择:
场景一:移动端 & 嵌入式应用
这是 SQLite 最经典的战场。Android 和 iOS 都内置了 SQLite 作为本地数据存储方案。你手机里的通讯录、短信、照片元数据、App 缓存——绝大多数都躺在 SQLite 数据库里。
┌──────────────┐ ┌──────────────┐
│ App 界面 │ │ SQLite DB │
│ (展示数据) │────→│ contacts.db │
│ │←────│ messages.db │
└──────────────┘ └──────────────┘
不需要网络,不需要服务器,离线也能用。场景二:桌面应用的本地存储
浏览器(Chrome、Firefox)用 SQLite 存储历史记录、书签、Cookie。微信桌面版用它存聊天记录。只要你的应用需要在本地存储结构化数据,SQLite 就是最省心的选择。
场景三:应用缓存与中间数据
Web 框架(如 Django)默认使用 SQLite 作为开发环境的数据库。测试框架用它来创建临时数据库做单元测试——用完即删,干净利落。
场景四:数据分析与科学计算
处理中等规模的数据集(几 GB 以内),SQLite 比 Pandas 读 CSV 更快、更省内存。你可以用 SQL 直接查询、聚合、JOIN,不用把所有数据加载到内存里。
场景五:原型开发与快速验证
创业公司做 MVP、学生做课程项目、后端开发写 Demo——用 SQLite 可以立刻开始,不用花时间搭建 MySQL。等产品验证成功了再迁移到生产数据库也不迟。
场景六:配置与元数据存储
用 SQLite 替代 JSON / XML 配置文件。好处是可以用 SQL 查询,支持事务(不会写一半崩溃导致配置文件损坏),而且还能建索引加速查找。
一句话概括:凡是需要 「应用本地结构化存储」 且 「不需要多客户端并发写入」 的场景,首选 SQLite。
1.4 SQLite vs MySQL / PostgreSQL —— 什么时候该用 SQLite
很多人会问:SQLite 这么好用,能不能拿来做 Web 项目的主数据库?答案取决于你的场景。
| 对比维度 | SQLite | MySQL / PostgreSQL |
|---|---|---|
| 部署方式 | 嵌入应用内,无需安装服务 | 独立服务器进程,需安装配置 |
| 数据存储 | 单个磁盘文件 | 服务器管理的文件系统 |
| 并发能力 | 多读单写(WAL 模式下可并发读) | 高并发读写 |
| 数据容量 | 理论 281 TB,实际适合 GB 级 | 轻松应对 TB 级 |
| 网络访问 | 不支持远程连接 | 支持网络访问 |
| 用户权限 | 无(依赖文件系统权限) | 完整的用户/角色/权限体系 |
| 运维成本 | 几乎为零 | 需要 DBA 或运维知识 |
| 适合场景 | 本地应用、嵌入式、原型、小型网站 | 生产环境、多用户 Web 应用 |
选择原则
问自己三个问题:
1. 需要多台服务器同时写入同一个数据库吗?
→ 是:用 MySQL / PostgreSQL
→ 否:继续看第二个问题
2. 需要支持远程网络连接?
→ 是:用 MySQL / PostgreSQL
→ 否:继续看第三个问题
3. 数据量会超过 10 GB、或并发写入 QPS > 100?
→ 是:用 MySQL / PostgreSQL
→ 否:SQLite 完全够用!一个有趣的趋势
近年来,SQLite 在 Web 场景中正在"逆袭":
┌─────────────────────────────────────────────────┐
│ SQLite 的 Web 新玩法 │
│ │
│ Litestream → 实时复制 SQLite 到 S3,实现容灾 │
│ LiteFS → 在多节点间同步 SQLite,支持只读副本 │
│ Turso → 把 SQLite 搬到边缘节点(Edge) │
│ libSQL → SQLite 的开源分叉,增强网络能力 │
│ │
│ 理念:每个用户一个 SQLite 文件,数据离用户最近 │
└─────────────────────────────────────────────────┘结论:SQLite 和 MySQL / PostgreSQL 是互补关系,不是替代关系。选择的核心依据是应用架构,而不是数据库性能。
1.5 SQLite 的整体架构概览
在深入学习之前,先建立一个对 SQLite 内部架构的整体认知。SQLite 的架构可以分为四层:
┌─────────────────────────────────────────────────────┐
│ 应用程序 │
│ sqlite3_exec("SELECT ...") │
└────────────────────┬────────────────────────────────┘
│ SQL 语句
↓
┌─────────────────────────────────────────────────────┐
│ ① 编译器层(Compiler) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ 分词器 │──→│ 解析器 │──→│ 代码生成器 │ │
│ │ Tokenizer │ │ Parser │ │ Code Generator│ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ │
│ 把 SQL 文本 → 解析成语法树 → 生成字节码 │
└────────────────────┬────────────────────────────────┘
│ 字节码
↓
┌─────────────────────────────────────────────────────┐
│ ② 虚拟机层(Virtual Machine / VDBE) │
│ │
│ 逐条执行字节码指令,类似 Java 的 JVM │
│ 这是 SQLite 的核心执行引擎 │
└────────────────────┬────────────────────────────────┘
│ 读/写数据请求
↓
┌─────────────────────────────────────────────────────┐
│ ③ 存储引擎层(B-Tree + Pager) │
│ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ B-Tree 模块 │────→│ Pager(页面管理器) │ │
│ │ 组织数据结构 │←────│ 管理缓存、事务、锁 │ │
│ └──────────────┘ └──────────┬───────────┘ │
│ │ │
│ 每个表和索引都是一棵 B-Tree │ │
└────────────────────────────────────┼─────────────────┘
│ 文件 I/O
↓
┌─────────────────────────────────────────────────────┐
│ ④ OS 接口层(VFS) │
│ │
│ Virtual File System —— 抽象文件操作 │
│ 不同操作系统用不同的实现(Unix / Windows) │
│ 负责:文件读写、文件锁、内存映射 │
└────────────────────┬────────────────────────────────┘
│
↓
┌──────────────┐
│ database.db │
└──────────────┘几个关键概念
页面(Page):SQLite 把数据库文件分割成固定大小的页面(默认 4096 字节)。所有数据的读写都以页面为单位。
数据库文件 = 一连串固定大小的页面
┌────────┬────────┬────────┬────────┬────────┐
│ Page 1 │ Page 2 │ Page 3 │ Page 4 │ ... │
│ (头页) │ (数据) │ (数据) │ (索引) │ │
└────────┴────────┴────────┴────────┴────────┘
↑
包含文件头信息(魔数、版本、页面大小等)B-Tree:每张表的数据和每个索引都组织成一棵 B-Tree。这让 SQLite 可以高效地按主键查找、范围扫描和有序遍历。
WAL(Write-Ahead Logging):写操作先记录到日志文件,再同步到主数据库文件。这是 SQLite 实现事务安全和并发读写的关键机制(后续章节会详细介绍)。
现在只需要记住:SQL 语句从输入到执行,经历了
编译 → 虚拟机执行 → B-Tree 读写 → 文件 I/O四个阶段。整个过程都发生在你的应用进程内部,没有网络通信。
本章小结
| 知识点 | 要点 |
|---|---|
| SQLite 本质 | 嵌入式关系型数据库引擎,单文件存储 |
| 设计哲学 | 零配置、无服务器、单文件、自包含 |
| 核心场景 | 移动端、桌面应用、缓存、数据分析、原型开发 |
| 与 MySQL/PG 的关系 | 互补而非替代,核心差异在部署架构而非性能 |
| 内部架构 | 编译器 → 虚拟机 → B-Tree/Pager → OS 接口(VFS) |
| 部署量 | 全球超过 1 万亿个活跃部署,最广泛的数据库引擎 |
下一章预告:动手把 SQLite 跑起来——安装、启动 sqlite3 命令行工具、执行你的第一条 SQL 语句。