原文: https://joecode.com/2026-08-19-sqlite3/,来源: https://www.ruanyifeng.com/blog/2026/08/weekly-issue-409.html

2026年8月19日

Raphael Bauer 博士撰写了一篇精彩的文章 ( 《PostgreSQL for Everything 》) ,阐述了使用 PostgreSQL 为企业提供强大支持的价值。我冒昧地纠正了其中的一些错误,主要是他应该选择 SQLite 😊(这主要是个玩笑,我非常喜欢 PostgreSQL,它是一项很棒的技术。)

与普遍认知相反,所有问题的答案并非 42,而是 SQLite。(好吧,也可能是 sqlite3 。)

目录

引言

SQLite 的寿命比你现在运行的绝大多数程序都要长。

当时人们普遍认为 SQLite 只是个玩具,一个文件,是塞进手机应用里的东西,这样就不用自己写配置解析器了。真正的应用需要的是真正的数据库,有真正的端口号、真正的守护进程,甚至还有凌晨三点的紧急页面。

依我拙见,SQLite 的强大之处源于以下三个方面:

  1. 它坚固稳定。
  2. 它易于运行、安装和扩展。主要是因为根本不需要运行任何东西。
  3. 它不仅是关系数据库管理系统,还是全文搜索引擎、文档存储、缓存、矢量索引和文件格式,从而大大简化了您的 IT 设置。

让我们仔细看看。

坚如磐石,稳定可靠

SQLite 是一项略显老旧的技术。它于 2000 年首次发布,但同时也是全球部署最广泛的数据库引擎,而且优势非常明显。你的手机里有它,你的浏览器里有它,你的汽车里有它,甚至你乘坐的飞机上也有它。SQLite 的运行实例数量比其他所有数据库加起来还要多,而且这根本毫无悬念。

修复数据库系统中的漏洞需要时间。SQLite 不仅有足够的时间,而且还持续改进。其测试套件在 MC/DC 标准(航空电子软件也采用该标准)下实现了 100% 的分支覆盖率。测试代码量大约是库代码量的 500 倍。该项目承诺持续支持到 2050 年,这比贵公司的使命宣言规划周期更长远。

它也是公共领域的。不是开源软件。是公共领域软件。没有许可证,没有贡献者许可协议,没有署名条款,也不是那种靠 C 轮融资后又改变主意的供应商。

没错,SQLite 的确很老了。但它一直在默默地推出各种现代功能:窗口函数、 RETURNING 函数、严格表结构、生成列、 jsonb 。每次发布都是一个经过充分测试、向后兼容的小幅改进,这对于数据库来说,既是最不起眼的,也是最有价值的。

易于运行、安装和扩展

从某种意义上说,在本地安装 SQLite 很简单,因为你已经安装过了。它与所有主流 Linux 发行版捆绑在一起,也内置于 Python、Ruby、PHP、Go、Rust、.NET、Android 和 iOS 等编程语言中,而且无论你是否需要,它现在就安装在你的 Mac 上。

针对与生产环境完全相同的数据库运行测试,这不是测试容器的问题,而是 :memory: 问题。你的测试套件会在几微秒内为每个测试并行启动一个全新的数据库,无需 Docker 守护进程,也不会出现端口冲突。你测试的对象就是你最终交付的对象,因为它们是同一个库编译成的同一个二进制文件。

如果你想在服务器上运行 SQLite:你已经在运行了。它随操作系统一起提供了。

扩展部分是大家预期文章会变得平淡的部分,所以我们不要让它平静下来:

  • 垂直整合: 一台配备 128GB 内存的现代 NVMe 固态硬盘,在数据库往返仅需一次函数调用而非网络跳转的情况下,就能处理惊人的流量。无需连接池,无需 TLS 握手,无需 pgbouncer 。处理速度以纳秒而非毫秒计算。
  • 复制和备份: Litestream 将 WAL 日志持续流式传输到 S3。LiteFS 提供分布式读取。两者都体积小、仅包含单个二进制文件,而且略显单调。
  • 托管服务商: Turso、Cloudflare D1、rqlite 等公司很乐意向您出售带有控制面板的 SQLite,如果您怀念控制面板的话。

这使得 SQLite 成为目前支持最广泛的软件之一。对您而言,这意味着更少的维护工作和更多的时间为客户开发功能。

简化您的 IT 设置

在云端运行 SQLite 完全无需点击,因为它就位于应用程序旁边的一个文件里。但这还不是全部。SQLite 可以取代你原本需要运行的一整套系统。

SQLite 取代 Solr 和 Elastic:全文搜索

SQLite 自带 FTS5,这是一个内置于您已链接的库中的全文搜索引擎。它还提供分词器、前缀查询、短语查询、 NEAR 、布尔运算符、使用 BM25 进行自定义排名以及用于渲染结果的摘要/高亮显示功能。

这里有两点值得注意。首先,不存在同步问题,因为没有第二个系统。根据定义,您的搜索索引会与您的数据在同一事务中更新,并且永久有效。您遇到的所有"为什么搜索索引过期"的问题,都是由您不需要的架构造成的。

其次,它的速度快得令人惊讶。Simon Willison 的 Datasette 可以在一台小型虚拟机上免费运行,对数 GB 的 SQLite 文件进行分面全文搜索,并在几毫秒内返回结果。

FTS5 会支持多语言分析链和跨 40 个节点的分布式分片吗?不会。你们有 40 个节点吗?也没有。

更多相关内容: SQLite FTS5 文档

SQLite 取代 MongoDB:出色的 JSON 支持

SQLite 对 JSON 的存储和查询提供了出色的支持。JSON 函数是内置的, -> 和 ->> 运算符的工作方式也符合预期,而且自 3.45 版本起,还新增了 jsonb ,这是一种二进制表示形式,每次访问时无需重新解析。

人们常常忽略的一点是:你可以对 JSON 进行索引。从 JSON 路径创建一个生成列,并为该生成列建立索引,这样即使你的模式中不存在某个字段,你也能快速查找它。无需模式即可写入,只需索引即可读取,一切尽在掌握。

所以,MongoDB 的优势在于:文档存储、ACID 事务、无需独立服务器、无需副本集、无需分片配置、无需 mongod ,磁盘上存储的只是一个可以复制的单个文件。那么,MongoDB 还有必要存在吗?之前有一篇不错的文章,讲述了一家大型出版机构弃用 MongoDB 的故事。值得注意的是,至今还没有人写过相反的例子。

SQLite 取代 Kafka 和 RabbitMQ:SQLite 作为队列

事件、队列和持久日志的重要性与日俱增。Kafka、RabbitMQ 和 SQS 都提供了这些功能。但维护它们既繁琐又需要定制化,而且需要专门的技能,因此你必须为此聘请专业人员。

好消息:桌子没问题。

BEGIN IMMEDIATE;
UPDATE jobs SET status = 'running', worker = ?
WHERE id = (SELECT id FROM jobs WHERE status = 'pending'
            ORDER BY id LIMIT 1)
RETURNING *;
COMMIT;

BEGIN IMMEDIATE 会预先获取写锁, RETURNING 会将已声明的行返回给你,并且该事务保证只有一个工作进程能够获取到该行。在 WAL 模式下,读取器永远不会阻塞,因此你的仪表板查询队列深度不会与工作进程发生冲突。

这里要坦诚地提醒一句,因为你值得了解:SQLite 只有一个写入器。它没有 SKIP LOCKED ,因为没有什么可以跳过的。并发的消费者会串行执行写入锁,如果你的入队速率真的达到每秒数万条,你就会感受到性能瓶颈。

但请注意发生了什么。在 PostgreSQL 版本中,队列是数据库中的一个表。而在这个版本中,队列不仅是数据库中的一个表,也是应用程序进程中的一个表。消息永远不会离开机器。没有消息代理,没有消费者组重新平衡,也不会出现"为什么部署期间分区分配发生了变化"的问题。

我的建议:先用 SQLite 作为队列。当它性能下降时,你会得到实际的数据,而不是凭感觉判断,这样你就可以放心地去购买 Kafka 了。你会惊讶于这需要多长时间。

SQLite 取代 Clickhouse:高容量时间序列数据

时间序列数据很特殊。大量数据点快速到达,然后进行聚合、统计和汇总。

这里没有 TimescaleDB,所以我们直说吧。SQLite 提供的是:

  • 按文件分区。 每天、每周或每个租户一个数据库。归档使用 mv 命令。删除旧数据使用 rm ,该命令以恒定时间运行,且不会执行 vacuum 操作。跨数据库查询使用 ATTACH 加上 UNION ALL 视图。这种方法虽然粗糙,但非常有效。
  • 汇总表由触发器或与插入操作相同的代码路径生成。无论如何,你本来就要构建连续聚合。
  • 批量写入。 一次事务,插入一万行数据,然后执行一次 fsync。在普通硬件上,SQLite 通过这种方式每秒可以处理数十万行数据,因为路径中没有网络协议。
  • 需要时支持列式存储。 对于分析部分,DuckDB 可以直接指向你的 SQLite 文件。它能原生读取该文件。这样,你就能在应用程序写入的同一个文件上获得向量化的 OLAP 功能,无需 ETL。

这些专用系统确实非常出色,如果你每秒要处理一百万个数据点,就应该去用用看。大多数人说的"时间序列"指的是每天几百万行数据,这对于固态硬盘上的文件来说,也就相当于周二的数据传输量。

SQLite 作为 AI 工作流的向量数据库

sqlite-vec 是一个单文件、无依赖项的扩展,可以将 SQLite 转换为向量数据库。它使用 C 语言编写,可以在任何 SQLite 运行的地方运行,包括通过 WASM 在浏览器中运行,并将向量存储在普通表中。

这正是 SQLite 的优势所在。你的词嵌入、源文档、元数据和全文索引都位于同一个文件中,因此混合搜索实际上是一个连接操作,而不是跨三个服务、采用三种不同一致性模型的分布式查询。只需一条语句,即可按租户、日期、关键词和向量相似度进行筛选,而且是事务性的。

此外,这一点比听起来更重要:你的整个 RAG 索引就是一个文件。你可以通过电子邮件发送它,可以将其放入 Docker 镜像中,甚至可以将其传输到离线的笔记本电脑上。试试用你的托管向量集群执行这些操作。

SQLite 取代 Redis:非持久化高性能缓存

缓存至关重要。大多数应用程序都使用 Redis 来保存会话和热点数据。缓存的定义允许数据丢失,并可以从源头重新生成。

那么,为什么要为此运行第二个服务器呢?SQLite 提供了多种选择,具体取决于你想牺牲多少数据持久性:

PRAGMA journal_mode = WAL;
PRAGMA synchronous = OFF;      -- it's a cache, live a little

或者完全跳过磁盘,使用 :memory: 或者使用 PRAGMA temp_store = MEMORY ,或者使用通过 file:cache?mode=memory&cache=shared 在连接之间共享的内存数据库。

Expiry 是一个列,并且有一个 DELETE ... WHERE expires_at < unixepoch() 定时删除,这正是 Redis 为你做的事情,只是距离更远,并且有它自己的驱逐策略,你需要去了解一下。

关键在于:通过本地主机向 Redis GET 请求大约需要 100 微秒,而对已缓存的页面进行 SQLite 点查询只需要 1 微秒。移除依赖项并没有导致速度变慢,反而提高了速度,因为最快的网络调用就是函数调用。

Redis 是一款优秀的软件。但它也是一个独立的进程,具有独立的故障模式、独立的内存预算、独立的安全防护机制,以及独立的成本项。

SQLite 取代文件系统:用于原始数据

你可能会认为从文件中读取一小段数据比从数据库中读取要快。但事实并非如此,这并非个人观点,而是 SQLite 项目发布的基准测试结果,其标题直截了当地写道:* 比文件系统快 35%* 。

对于小于约 100KB 的数据块,SQLite 的读写速度比磁盘上的单个文件更快,并且占用空间也少约 20%。这是因为文件系统对每个数据块都收取一次 open() 、一次 close() 调用和一次目录遍历的费用,而 SQLite 只收取一个已打开文件句柄和一次 B 树查找的费用。

你还可以免费获得:原子多 blob 更新、崩溃时不会进行部分写入、不会出现文件名转义错误、不会出现"当目录有 400 万个条目时会发生什么"的问题、不会因为 inode 计数而导致 rsync 花费 6 个小时,以及一个只有一个文件的备份故事。

将有效负载存储在 BLOB 列中,如果需要更精细的操作,可以使用更紧凑的序列化方式,然后在客户端进行反序列化。SQLite 团队自己也认为 SQLite 比 fopen() 更优秀,而且他们将其视为设计目标,并非玩笑。

SQLite 取代您的图数据库

在 SQL 中使用递归查询处理分层数据是可行的,但从历史上看,读取、维护和调试这些数据都非常痛苦。

SQLite 完全支持递归 CTE,其相关文档堪称业内顶尖的技术文档之一。闭包表、物化路径和邻接表都能很好地工作。由于没有 LTREE ,物化路径由一个 TEXT 列和一个 GLOB 索引构成,这种方式不够优雅,速度也大致相同。

对于实际的图论工作, simple-graph 仅用几百行 SQL 代码就在普通的 SQLite 表之上实现了一个属性图。节点、边、遍历。

这条原则在这里比在其他任何地方都更适用:你的图可能有上万个节点。上万个节点可以装进 L3 缓存。你不需要 Neo4j。你只需要一个索引和一杯咖啡。

SQLite 取代你的微服务

如今大多数"微服务"都是:一个模型、一个查询和 JSON 输出。

SQLite 使用 json_object() 和 json_group_array() 将任何查询转换为 JSON。这样一来,序列化层就消失了。

但 SQLite 的优势远不止于此,因为它运行在你的进程*内部 *。微服务并非被存储过程取代,而是被函数调用取代。无需部署服务,无需健康检查,无需重试逻辑,无需熔断器,无需关联分布式跟踪,也无需处理受网络抖动影响的 p99 数据。

Datasette 将概念验证推向了极致:只需指向一个 SQLite 文件,即可获得 JSON API、Web 用户界面、分面搜索以及插件生态系统,无需编写任何代码。Litestream 则负责数据持久化。这套生产级数据服务仅需两个二进制文件和一个文件即可完成。

凡事有利有弊,我不会否认弊端是不存在的。但在这个行业里,仅仅为了在查询前增加一次网络跳转而存在的服务数量并不少。

用 SQLite 替换你的 PlayStation 5

SQLite 文档本身就包含一个用递归公共表表达式编写的 Mandelbrot 集渲染器。在手册中。作为查询语法的示例。顺便提一下。

人们还用纯 SQLite CTE 实现了康威生命游戏、数独求解器和迷宫生成器。甚至还有国际象棋引擎。有人甚至在查询中实现了 Doom 的火焰特效。

太疯狂了。或许不必太当真。但你不得不佩服一个官方文档里都包含分形的数据库。

结论

以上列表并不完整。SQLite 是一款非常灵活的软件,它可以加载扩展程序,而且很可能总能找到适合您即将安装的服务器用途的扩展程序。

原论点说得对,而 SQLite 更胜一筹:简洁性才能让你快速行动。你的技术栈中的每个系统都需要部署、监控、保护、升级、备份、付费,还要向新员工解释。PostgreSQL 简化了这些工作。SQLite 则将其简化到零,因为数据库不是一个系统,而是一个文件和一个函数调用。

是的,确实存在瓶颈。一个作者,一台机器。当你达到这个瓶颈时,你自然会知道,然后你会去使用 PostgreSQL,那将是值得庆幸的一天,因为这意味着有人在用你的作品了。

在此之前,当下一个需求出现时,问问自己:SQLite 能不能做到这一点?我们真的需要那项闪亮的新技术 X 吗?

SQLite 或许并非万能,但它能解决的问题远比你想象的要多,而且它已经安装在你的电脑上了。

留言(0 条)

还没有留言,来写第一条吧

使用 GitHub 登录后即可在下方直接留言