大家对 SQLite 的看法都错了
这里有个大胆的观点:SQLite 可能是你下一个 SaaS 项目的最佳数据库选择。没错,就是这样。这个用来存储浏览器历史记录的数据库,处理生产环境工作负载的能力,可能比你正在考虑的那个过度设计的 Postgres 集群还要强。
在你厌恶地关闭这个页面之前,请听我解释。我亲眼目睹无数开发者一边把 SQLite 贬低为“玩具数据库”,一边却苦于连接池、复制延迟以及每月 500 美元的数据库费用。与此同时,像 Expensify 这样的公司却在 SQLite 上处理着价值 100 亿美元的交易。
问题不在于 SQLite,而在于我们一直以来对它的理解完全错误。
“轻量级”问题
让我们直面这个显而易见的问题:名字里那个不幸的“lite”。这就像把一辆跑车命名为“慢速迈凯伦”——从某种狭义的角度来看,技术上没错,但却完全误导了人们对它实际性能的认知。
SQLite 不是“Postgres 精简版”或“MySQL 入门版”,它完全是另一种类型的数据库。Postgres 是为客户端-服务器架构设计的,需要网络协议和连接管理,而 SQLite 则是一个嵌入式数据库引擎。它之所以更轻量级,并非因为功能更少,而是因为它不需要完整的服务器进程、网络协议栈和身份验证系统。
这就是 SQLite 的真正含义:
- 全球部署量最大的数据库引擎(数十亿个实例)
- 经受住了处理数百万次请求的公司在生产环境中的实战考验
- 对于许多工作负载而言,速度比客户端-服务器数据库更快
- 符合 ACID 标准,并提供完整的交易支持
- 能够处理高达 281TB 的数据库
但当然,就因为这个名字,我们就继续称它为玩具吧。
当 SQLite 完全碾压它时
传统观念在这里产生了偏差。SQLite 不仅“足够好”以应对某些用例,而且在许多生产场景中,它实际上是更优的选择:
1. 读取密集型工作负载
如果你的应用95%都是读取操作(就像大多数SaaS应用一样),SQLite会让你的Postgres配置相形见绌。它没有网络往返,没有连接开销,直接读取磁盘数据,并配备智能页面缓存。我亲眼见过,仅仅从Postgres切换到SQLite,查询时间就从50毫秒降到了0.5毫秒。
2. 单服务器部署
所有程序都运行在一台性能强大的服务器上?SQLite 可以解决一整类问题:
- 连接池未耗尽
- 无网络延迟
- 没有裂脑情景
- 无复制延迟
- 备份实际上就是复制一个文件。
3. 边缘计算
部署到多个区域?每个边缘节点都可以拥有自己的 SQLite 数据库。Cloudflare Workers、Fly.io 和类似平台让这一切变得轻而易举。您的用户可以享受低于 10 毫秒的响应时间,而您则可以获得简洁的架构。
4. 嵌入式分析
需要处理用户数据?SQLite 可以处理 GB 级数据的复杂分析查询。窗口函数、CTE、JSON 操作——应有尽有。而且速度很快,因为它没有网络开销。
真正的局限性(并非你所想)
让我们坦诚地谈谈 SQLite 的不足之处,因为这并非大多数人所想的那样:
❌ 高写入并发(但事情并非那么简单)
SQLite 采用单写模型,一次只能写入一个数据。但批评者不会告诉你的是:自从引入预写式日志(WAL)模式后,SQLite 可以在写入的同时处理并发读取操作。写入过程中不再会出现阻塞读取的情况。
在 WA 模式下:
- 作者不会阻碍读者。
- 读者不会阻碍作者。
- 多个阅读器同时工作
- 写入性能显著提升
-- 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”——错误。SQLite自 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
}
模式二:每个租户一个数据库
// 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内存和1TB存储空间很便宜)。
- 您重视简洁性和可靠性。
- 您希望最大限度地减少运营成本。
- 您正在构建嵌入式或边缘应用程序
- 你需要始终保持亚毫秒级的查询速度
以下情况请勿使用 SQLite:
- 你需要高写入并发性(持续每秒写入次数超过 1000 次)
- 您需要来自不同服务器的多个写入器
- 你需要内置的复制功能(虽然也有 LiteFS)。
- 您需要数据库级别的访问控制
无人提及的剧情反转
这里有个不为人知的秘密:大多数使用 Postgres 的初创公司其实用 SQLite 会更好。他们为并不需要的分布式系统复杂性买单,而性能却比不上简单的 SQLite 配置。
我已将多个生产系统从 Postgres 迁移到 SQLite。结果:
- 查询速度提升 10 倍(无需网络跳转)
- 运营复杂性降低 90%。
- 每月节省 500 美元数据库管理费用
- 备份/恢复时间从数小时缩短至数秒
- 连接池问题导致零停机
停止思考客户端-服务器架构
最大的思维转变在于:不要再把 SQLite 看作数据库服务器。它不是。它是一个恰好实现了 SQL 数据库的库。一旦你理解了这一点,一切就都明白了。
你不会为 JSON 解析器单独搭建一个服务器,也不会为正则表达式引擎创建连接池。那么,既然 SQLite 可以作为一个库来处理你的工作负载,为什么还要为数据库这样做呢?
未来已来
各大平台都在大力投资 SQLite:
- Cloudflare 的持久对象使用 SQLite。
- Fly.io 的 LiteFS 支持分布式 SQLite
- Turso 正在构建一个分布式 SQLite 平台
- 就连 Rails 也正在将 SQLite 作为生产环境的默认数据库。
这些不是玩具项目,而是服务于数十亿次请求的生产基础设施。
你的行动
在下一个项目中默认选择 Postgres 之前,请先问问自己:
- 你真的能保持每秒超过 1000 次的持续写入速度吗?
- 真的需要多个应用服务器写入同一个数据库吗?
- 对于您的使用场景而言,这种操作上的复杂性是否值得?
如果你对以上任何问题回答“否”,那么请认真考虑一下 SQLite。它不是通往“真正”数据库的过渡方案,而是作为你的生产数据库。
SQLite 中的“lite”并不意味着它的功能较弱,而是指它包含的代码更少。在生产环境中,更少的代码意味着更快的速度、更高的可靠性和更长的运行时间。
别想太多。先从 SQLite 开始。如果以后真的需要更复杂的功能,可以随时添加。但很可能你根本用不上。
一位选择Postgres的人的自述(以及原因)
我开发了UserJot,一个反馈管理平台。我们使用 Postgres,原因很简单:我们需要多服务器可扩展性,严重依赖 pgvector 进行语义搜索,使用 LISTEN/NOTIFY 进行实时更新,并且需要对数百万个数据点运行复杂的分析查询。
但我还完全基于 SQLite 构建了一个博客平台。它采用单二进制部署,通过 Litestream 复制到 S3,在每月 5 美元的 VPS 上实现了完美的扩展。运维起来非常轻松,正是因为 SQLite 消除了所有复杂性。
教训是什么?我为UserJot选择 Postgres是因为我们的特定需求需要它。而对于博客平台来说,SQLite 显然是最佳选择。大多数项目更像是博客平台,而不是UserJot。
选择枯燥乏味的技术,但要刻意选择它。
文章来源:https://dev.to/shayy/everyone-is-wrong-about-sqlite-4gjf
