核心问题
SQLite 不是缩小版的 Postgres,而是另一种形态的工具。整个数据库就是磁盘上的一个文件,你的应用程序通过链接进同一进程的库来访问它:没有服务器,没有网络,也没有用户。这种设计让 SQLite 在某些工作上表现出色,在另一些工作上则并不合适。
真正起决定作用的问题几乎从来不是“SQLite 够不够快?”(通常够快),而是“我的应用的形态和 SQLite 擅长的事情是否吻合?”这主要取决于两点:数据放在哪里,以及同一时间有多少个程序在写入。
数据和应用在一起时,用 SQLite
当数据库只属于一台机器上的一个应用时,SQLite 最能发挥优势。文件就放在你的代码旁边,应用直接打开它,这就是全部架构。
这个小小的结构完全可以是一个真实应用的全部后端。以下几种情况天然适合这种模式:
- 桌面和移动应用。 每个需要结构化本地存储的 iOS 和 Android 应用,底层用的都是 SQLite。Firefox、Chrome 和大多数浏览器也是如此。
- 命令行工具。
git、包管理器和 dotfile 管理工具都使用嵌入式数据库。 - 嵌入式设备。 路由器、汽车、飞机,凡是需要在几百 KB 的体积里放一个数据库的地方。
- 测试套件。 每个测试用一个新的 SQLite 文件(或
:memory:数据库),比启动 Postgres 更快,隔离性也更好。
如果你的数据不需要在多台机器之间共享,SQLite 很可能就是正确答案。
读多写少的网站,用 SQLite
SQLite 处理读取非常出色:大量并发读取者,没有争用,带索引的查找只需微秒级时间。如果你的网站主要是让人来读内容,比如博客、文档、营销网站、小型 SaaS 仪表盘,SQLite 完全撑得住,而且因为省去了网络往返,往往比通过网络连接的 Postgres 表现更好。
问题出在写入上。SQLite 会把写入串行化,同一时间只有一个写入者能持有锁。对于只有几位作者的博客,你根本感觉不到;但对于每秒有成千上万用户发消息的聊天应用,这就成了问题。
WAL 模式(预写日志,后面会讲)让读取者和写入者可以并行工作,大大提高了上限。很多生产网站用 SQLite 加 WAL,每天处理数百万次请求。
本地缓存和临时数据,用 SQLite
只要你需要结构化的本地存储,比 JSON 文件强、又用不着完整的数据库服务器,SQLite 就很难被超越。
日志、分析数据缓冲、ETL 中转、机器学习特征存储、IDE 索引,这些都很适合放进 SQLite。文件可以随处移动,查询语言是完整的 SQL,也没有需要照看的服务器。
大量并发写入者,别用 SQLite
这是最容易让人踩坑的限制。SQLite 使用数据库级的写锁:只能有一个写入者,没有例外。两个进程同时插入,其中一个就得等。
对大多数应用来说这无关紧要,因为写入既少又快。但如果你的工作负载是这样的:
- 成千上万用户同时写入的多租户 SaaS;
- 高吞吐量的消息队列或事件日志;
- 状态不断变化的实时游戏或聊天后端;
那么 SQLite 就会成为瓶颈。Postgres 和 MySQL 使用行级锁,正是为这种场景设计的,这时就该用它们。
-- The error you'll see when writers pile up:
Error: database is locked
如果在正常负载下就看到这个错误,说明 SQLite 选错了工具,而不是一个需要绕过去的 bug。
跨多台机器,别用 SQLite
SQLite 是一个进程内的库。应用直接读写文件,这意味着文件必须放在应用能用普通文件系统调用 read() 和 write() 的磁盘上。
这就排除了以下情况:
- 负载均衡器后面的多台应用服务器都想共享同一个数据库。(NFS 这类网络文件系统理论上能用,但在负载下会损坏文件。千万别这么做。)
- Serverless 函数,每次调用都可能运行在不同的机器上。
- 需要共享数据库的 Kubernetes Pod,除非你只部署单个 Pod 并挂载持久卷。
如果你的架构里有多台机器上的多个进程在写入数据库,你就需要客户端/服务器数据库。界线就在这里。
需要数据库级用户时,别用 SQLite
SQLite 没有用户、角色或权限的概念。数据库就是一个文件:谁能读这个文件,谁就能读到全部内容;谁能写这个文件,谁就能改动全部内容。访问控制由操作系统负责。
对单用户的桌面应用来说,这没问题。但对于不同的人在数据库内部需要不同权限的多租户系统,你需要 Postgres 或 MySQL。
快速决策清单
逐条过一遍这份清单。如果每一条的答案都是“是”,SQLite 很可能是个很好的选择:
- 数据库和应用程序在同一台机器上。
- 只有一个进程(或少数几个、以读取为主的进程)访问它。
- 全部数据可以轻松放进一块磁盘:几个 TB 也没问题,但终归是一块磁盘。
- 你不需要数据库级的用户权限。
- 并发写入只是偶尔发生,而不是主要的工作负载。
只要有一条答案是“否”,就去看看 Postgres 或 MySQL。接下来的两页会直接对比它们。
本篇要点
- 当数据库是应用本地的数据库时,SQLite 就是正确的选择:桌面、移动、嵌入式、命令行工具、测试套件、读多写少的网站和本地缓存。
- 它达到生产级水准,数十亿台设备都内置了它。它的约束来自架构,与质量无关。
- 当你需要大量并发写入者、多机访问或按用户划分的数据库权限时,就别用它。
下一篇:安装 SQLite
理论讲够了。下一页会带你把 SQLite 装到电脑上(macOS 和大多数 Linux 发行版已经自带,Windows 上也只需下载一次),并在命令行里确认安装成功。
常见问题
什么时候应该用 SQLite?
当数据和应用程序放在一起时就用 SQLite:桌面应用、移动应用、命令行工具、嵌入式设备、中小型网站、本地缓存和测试套件。只要是单个进程(或少数几个以读取为主的进程)需要一个真正的 SQL 数据库、又不想单独运行服务器,它都非常合适。
SQLite 适合用在生产环境吗?
适合,只要工作负载的形态对路。每一部 iPhone、每一台 Android 设备和大多数浏览器都内置了 SQLite,也有大量生产网站靠它运行。它的限制不在可靠性,而在并发:整个数据库同一时间只能有一个写入者,而且数据库文件必须和应用放在同一台机器上。
什么时候不该用 SQLite?
当你需要大量并发写入者、数据库必须能被多台应用服务器通过网络访问,或者需要细粒度的用户权限时,就别用 SQLite。这些正是 Postgres 和 MySQL 生来要做的事。