不妨大胆一点:SQLite 或许是你下一个 SaaS 项目的最佳数据库选择。没错,真的。支持浏览器历史记录的数据库,甚至比你正在考虑的那个过度设计的 Postgres 集群,更能处理你的生产工作负载。
在你厌恶地关闭这个标签页之前,先听我说完。我见过无数开发者将 SQLite 视为“玩具数据库”,同时还要应对连接池、复制延迟以及每月 500 美元的数据库账单。与此同时,像 Expensify 这样的公司正在使用 SQLite 处理价值 100 亿美元的交易。
问题不在于 SQLite,而在于我们对它的理解完全错误。
“Lite”的问题
让我们来谈谈这个显而易见的问题:名字里那个令人遗憾的“lite”。这就像把一辆跑车命名为“Slow McLaren”——从某种狭义上讲,技术上准确,但对其实际性能却完全误导。
SQLite 并非“Postgres Lite”或“MySQL 入门版”,而是完全不同的另一类数据库。Postgres 是为客户端-服务器架构构建的,带有网络协议和连接管理功能,而 SQLite 是一个嵌入式数据库引擎。它并非因为功能更少而更轻量,而是因为它不需要完整的服务器进程、网络堆栈和身份验证系统。
SQLite 实际上是这样的:
- 世界上部署最多的数据库引擎(数十亿个实例)
- 在处理百万级请求的生产环境中经过实战检验
- 对于许多工作负载来说,速度比客户端-服务器数据库更快
- 符合 ACID 规范并支持完整事务
- 能够处理高达 281TB 的数据库
但当然,因为这个名字,我们继续称它为玩具。
当 SQLite 彻底击败它时
这就是传统观点的反面。SQLite 不仅仅是在某些用例下“足够好”——实际上,它是许多生产场景的更佳选择:
1. 读取量大
如果您的应用 95% 都用于读取(就像大多数 SaaS 应用一样),那么 SQLite 将使您的 Postgres 设置黯然失色。无需网络往返,没有连接开销。只需使用智能页面缓存直接读取磁盘即可。我亲眼见证过,仅仅通过从 Postgres 切换到 SQLite,查询时间就从 50 毫秒缩短到了 0.5 毫秒。
2.单服务器部署
把所有东西都放在一台强大的服务器上?SQLite 可以解决一系列问题:
- 无需担心连接池耗尽
- 无网络延迟
- 无脑裂场景
- 无复制滞后
- 备份就是简单地复制一个文件
3.边缘计算
部署到多个区域?每个边缘位置都可以拥有自己的 SQLite 数据库。Cloudflare Workers、http://Fly.io 和类似平台让这一切变得轻而易举。你的用户将获得低于 10 毫秒的响应时间,而你则拥有简洁的架构。
4.嵌入式分析
需要对用户数据进行数字运算?SQLite 可以处理 GB 级数据的复杂分析查询。窗口函数、CTE、JSON 操作——应有尽有。而且速度很快,因为没有网络开销。
真正的限制(并非你所想的那样)
让我们坦诚地谈谈 SQLite 的困难之处,因为它并不像大多数人想象的那样:
没有高写入并发性(但这并不那么简单)
SQLite 使用单写入模型,即每次只写入一个数据。但反对者们没有告诉你的是:自从引入预写日志 (WAL) 模式以来,SQLite 可以在写入的同时处理并发读取。写入期间不再阻塞读取。
在 WAL 模式下:
- Writers不会阻碍Reader
- Reader不会阻碍Writers
- 多个Reader能同时工作
- 写入性能大幅提升
-- Enable WAL mode (do this once)
PRAGMA journal_mode=WAL;
在启用 WAL 并进行适当配置的情况下,我发现 SQLite 在现代硬件上每秒可以处理 500-1000 次以上的写入操作,同时还能处理数千次并发读取。没错,Postgres 可以通过多个写入器实现更高的写入速度,但问问自己:你的 SaaS 每秒真的能处理超过 1000 次写入操作吗?(剧透:没有。)
无法实现多个应用服务器水平扩容
需要跨多台服务器进行水平扩展,并访问同一个数据库吗?SQLite 并非为此而生。您需要 Postgres 或 MySQL。(不过,像 LiteFS 和 rqlite 这样的解决方案正在改变这一现状。)
没有复杂的访问控制
SQLite 没有用户、角色或行级安全性。你的应用程序处理所有授权。对于 99% 的 SaaS 应用来说,这实际上没有问题,因为这些应用无论如何都会在代码中检查权限。
但人们的错误在于:
- “SQLite 无法处理并发读取”——错误。它可以处理无限的并发读取。
- “SQLite 不支持 JSON”——错误。自 2015 年起全面支持 JSON。
- “SQLite 无法进行全文搜索”——错了。FTS5非常出色。
- “SQLite 数据库很容易损坏”——错了。它是迄今为止最可靠的存储格式之一。
改变一切的架构
以下是在生产环境中考虑 SQLite 的方法:
Traditional Architecture:
App Server → Network → Database Server → Disk
SQLite Architecture:
App Server → Disk
就是这样。你的数据库查询现在是函数调用。你的“连接”是一个文件句柄。你的备份系统是cp database.db backup.db。
这种简洁并非限制,而是一种超能力。您移除的每个组件都不会发生故障,不会出现配置错误,也无需监控。
你从未想过的运营梦想
让我们来讨论一些能让您的 DevOps 团队喜极而泣的事情:SQLite 操作。
备份?它只是一个文件
# Your entire backup strategy
cp production.db backup-$(date +%Y%m%d).db
# Or get fancy with point-in-time recovery using Litestream
# Streams every change to S3 automatically
litestream replicate production.db s3://mybucket/db
就是这样。无需 pg_dump。无需协调副本。无需担心备份一致性。使用 Litestream,你可以持续复制到 S3,并支持时间点恢复。只需 5 分钟即可完成设置,无需再操心。
恢复?甚至更容易
# Restore from yesterday
cp backup-20250115.db production.db
# Or restore from S3 with Litestream
litestream restore -o production.db s3://mybucket/db
这与恢复 50GB 的 Postgres 数据库相比,我还是会等。
测试?使用真实生产数据
# Clone prod for testing
cp production.db test.db
# Done. Full production dataset. Zero config.
无需清理连接字符串。无需管理测试数据库服务器。无需向财务部门解释为什么需要另一个 RDS 实例进行暂存。
监控?什么监控?
- 没有连接池指标
- 无复制滞后
- 没有长时间运行的查询警报
- 无吸尘计划
- 无磁盘空间警报
只有真正重要的应用指标。
实际生产模式
模式 1:直写缓存
// Instead of complex Redis + Postgres setups
async function getUser(userId: string) {
return db.get("SELECT * FROM users WHERE id = ?", userId);
// SQLite *is* your cache with 0ms latency
}
模式 2:租户数据库
// Each customer gets their own SQLite database
function getCustomerDb(customerId: string) {
return new Database(`./data/customers/${customerId}.db`);
// Perfect isolation, easy backups, simple compliance
}
模式3:混合架构
// SQLite for reads, Postgres for writes
// Stream changes from Postgres to SQLite replicas
// 99% of queries hit SQLite, 1% hit Postgres
const read = async (query: string) => sqlite.get(query);
const write = async (query: string) => postgres.execute(query);
最佳选择:何时使用 SQLite
在以下情况下使用 SQLite:
- 读取操作占绝大多数 (>90% 读取)
- 您可以在一台服务器上安装(现在最多 100GB RAM 和 1TB 存储空间很便宜)
- 您重视简单性和可靠性
- 您希望最大限度地减少运营开销
- 您正在构建嵌入式或边缘应用程序
- 您需要一致的亚毫秒级查询时间
在以下情况下不要使用 SQLite:
- 您需要较高的写入并发性(持续每秒写入次数 >1000 次)
- 您需要来自不同服务器的多个写入器
- 您需要内置复制(尽管存在 LiteFS)
- 您需要数据库级访问控制
没人谈论的剧情转折
有个不为人知的秘密:大多数使用 Postgres 的初创公司都更倾向于使用 SQLite。他们为不必要的分布式系统复杂性付出了代价,而性能却比简单的 SQLite 设置更差。
我已经将几个生产系统从 Postgres 迁移到 SQLite。结果:
- 查询速度提高 10 倍(无网络跳跃)
- 操作复杂性降低 90%
- 每月节省 500 美元的托管数据库成本
- 备份/恢复时间从几小时缩短至几秒钟
- 连接池问题导致零停机
别再想着客户端-服务器了
最大的思维转变是:别再把 SQLite 想成一个数据库服务器了。它不是。它只是一个恰好实现了 SQL 数据库的库。一旦你理解了这一点,一切都会水到渠成。
你不会为 JSON 解析器搭建单独的服务器,也不会为正则表达式引擎创建连接池。既然 SQLite 可以作为一个库来处理你的工作负载,为什么还要为数据库创建连接池呢?
未来已来
各大平台都大力支持 SQLite:
- Cloudflare 的 Durable Objects 使用 SQLite
- http://Fly.io 的 LiteFS 支持分布式 SQLite
- Turso 正在构建分布式 SQLite 平台
- 甚至 Rails 也力推 SQLite 作为生产默认语言
这些不是玩具项目。它们是服务于数十亿请求的生产基础设施。
你的举动
在将下一个项目默认使用 Postgres 之前,请问自己:
- 您每秒真的会有 >1000 次持续写入吗?
- 您是否确实需要多个应用服务器写入同一个数据库?
- 对于您的用例来说,操作复杂性是否值得?
如果你对其中任何一个问题的回答是“否”,那么请认真考虑一下 SQLite。它不是作为“真正”数据库的垫脚石,而是作为你的生产数据库。
SQLite 中的“精简”并不意味着它功能不足,而是指它负担更少。在生产环境中,更少的负担意味着更快的速度、更高的可靠性和更多的睡眠。
别想太多了。先从 SQLite 开始吧。以后如果真的需要,可以随时添加复杂性。但很可能你不会这么做。
但我也完全基于 SQLite 构建了一个博客平台。单一二进制部署,Litestream 复制到 S3,在每月 5 美元的 VPS 上实现了完美的扩展。操作起来非常愉快,正是因为 SQLite 消除了所有的复杂性。
教训是什么?我为另一个项目选择了 Postgres ,因为我们的具体需求决定了它。对于博客平台来说,SQLite 显然是最佳选择。大多数项目都更像博客平台。
选择无趣的技术,但要慎重选择。
本文为译文,英文原文地址(可能需要使用魔法访问或付费会员才可观看):
https://dev.to/shayy/everyone-is-wrong-about-sqlite-4gjf