从零开始的 SQLite 学习笔记,覆盖核心概念、SQL 用法、应用场景与最佳实践。
图表在
/SQLite学习笔记/diagrams/目录。
📌 打个比方:MySQL/PostgreSQL 像银行金库——需要管理员、需要保安、需要排队窗口。SQLite 像保险箱——放在你办公室里,钥匙在你手里,随开随关,不需要任何人帮忙。
📌 SQLite 无处不在:你的手机(Android/iOS app 数据存储)、浏览器(Chrome 的 cookie/history)、Python(标准库自带)、飞机娱乐系统、IoT 设备……世界上部署量最大的数据库,没有之一。
| 特性 | SQLite | MySQL / PostgreSQL |
|---|---|---|
| 架构 | 嵌入式(进程内) | 客户端-服务器(C/S) |
| 安装 | 零安装 | 需安装配置 |
| 服务 | 无独立进程 | 需启动数据库服务 |
| 端口 | 无 | 3306 / 5432 |
| 存储 | 单个文件 | 多文件 + 内存 |
| 并发 | 单写多读(WAL 模式) | 高并发读写 |
| 网络访问 | 不支持(本地) | 支持 |
| 适用规模 | GB 级 | TB 级 |
| 用户管理 | 无 | 完善的权限系统 |
| 成本 | 零 | 需运维 |
📌 什么时候用 SQLite:① 移动端 app 本地存储 ② 桌面应用数据 ③ 小型网站(日 PV < 10万)④ 配置/缓存存储 ⑤ 测试/原型 ⑥ 数据分析(替代 CSV)⑦ 嵌入式设备
📌 什么时候不该用 SQLite:① 高并发写入(多线程频繁写)② 需要网络远程访问 ③ 数据量 TB 级 ④ 需要复杂用户权限管理 ⑤ 需要存储过程/触发器等高级特性
📌 SQLite 数据库就是一个文件:mydb.sqlite 就是整个数据库。复制这个文件 = 备份。删除这个文件 = 销毁。不需要 mysqldump,不需要 pg_dump。
📌 UPSERT 是 SQLite 的实用功能:ON CONFLICT DO UPDATE 一步完成"不存在则插入,存在则更新"。MySQL 用 INSERT ... ON DUPLICATE KEY UPDATE,PostgreSQL 用 INSERT ... ON CONFLICT DO UPDATE,语法略有不同。
📌 WITHOUT ROWID:默认 SQLite 每张表有个隐式的 rowid 列。如果主键就是你要查的列(如配置表的 key),用 WITHOUT ROWID 可以省掉 rowid 的存储和索引开销。
SQLite 与其他数据库最大的区别:**类型亲和(Type Affinity)**而非严格类型。
| 声明类型 | 亲和类型 | 说明 |
|---|---|---|
| INT, INTEGER | INTEGER | 整数 |
| TEXT, VARCHAR, CHAR | TEXT | 文本 |
| BLOB | BLOB | 二进制 |
| REAL, FLOAT, DOUBLE | REAL | 浮点数 |
| (无声明)/ NUMERIC | NUMERIC | 数字(整数或浮点) |
📌 动态类型的利与弊:利——灵活,迁移方便。弊——可能存入意外类型导致 bug。建议:虽然 SQLite 允许混存,但应用层应严格保证类型一致。
SQLite 实际有 5 种存储类:NULL、INTEGER、REAL、TEXT、BLOB。没有 Boolean,用 0(false)和 1(true)。没有 Date 类型,用 TEXT(ISO 8601)、INTEGER(Unix 时间戳)或 REAL(Julian Day)存储。
📌 SQLite 索引也是 B-Tree,与 MySQL 类似。最左前缀原则同样适用。但 SQLite 没有 EXPLAIN 的详细输出(只有 QUERY PLAN),分析能力不如 MySQL/PG。
SQLite 的事务是 ACID 合规的。默认每个 SQL 语句自动包裹在隐式事务中。
| 模式 | 说明 | 并发能力 |
|---|---|---|
| DELETE(默认) | 写时删除回滚日志 | 读+写互斥 |
| WAL(推荐) | Write-Ahead Logging | 读不阻塞写,写不阻塞读 |
| TRUNCATE | 类似 DELETE,提交后截断日志 | 同 DELETE |
| MEMORY | 日志在内存 | 最快,但崩溃可能丢数据 |
📌 WAL 模式是 SQLite 并发的关键:默认模式下读写互斥,一个线程写时其他线程连读都不行。WAL 模式下读和写可以并行——读操作读旧快照,写操作追加到 WAL 文件。生产环境务必开启 WAL。
📌 SQLite 的并发限制:即使 WAL 模式,同时只能有一个写操作。多个读可以并发,但写必须排队。这是 SQLite 不适合高并发写入的根本原因。
📌 参数化查询防注入:永远用 ? 占位符,不要用字符串拼接 SQL。f"SELECT * FROM users WHERE name = '{name}'" 有 SQL 注入风险,WHERE name = ? 则安全。
📌 批量插入性能差异巨大:1 万条数据,逐条提交可能要 10 秒,批量提交只需 0.1 秒。因为 SQLite 每次提交都要 fsync 刷盘,批量提交只刷一次。
| PRAGMA | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
journal_mode |
DELETE | WAL | 读写并发 |
synchronous |
FULL | NORMAL | WAL 下安全且快 |
cache_size |
-2000(2MB) | -64000(64MB) | 更大缓存 |
temp_store |
0 | MEMORY | 临时表在内存 |
mmap_size |
0 | 268435456 | 内存映射 I/O |
WITHOUT ROWID:主键是文本/UUID 时省空间SELECT COUNT(*):大表 COUNT 慢,维护一个计数器表INSTEAD OF 触发器实现可更新的视图| 工具 | 说明 |
|---|---|
| DB Browser for SQLite | 免费开源 GUI(推荐) |
| DBeaver | 多数据库 GUI,支持 SQLite |
| TablePlus | 现代化数据库 GUI |
| VS Code SQLite 插件 | 编辑器内查看 SQLite |
| 语言 | 库 |
|---|---|
| Python | sqlite3(标准库)、SQLAlchemy |
| Node.js | better-sqlite3、sqlite3 |
| C/C++ | sqlite3.h(C API) |
| Rust | rusqlite |
| Go | modernc.org/sqlite(纯 Go) |
| Java | JDBC + sqlite-jdbc |
| 操作 | 命令/语法 |
|---|---|
| 创建数据库 | sqlite3 mydb.sqlite |
| 内存数据库 | sqlite3 :memory: |
| 查看表 | .tables |
| 查看建表语句 | .schema table_name |
| 导出 | .dump > backup.sql |
| 开启 WAL | PRAGMA journal_mode = WAL; |
| 压缩 | VACUUM; |
| UPSERT | INSERT ... ON CONFLICT DO UPDATE |
| 附加数据库 | ATTACH DATABASE 'file' AS alias; |
| 参数化 | WHERE col = ? |