如果你仍然认为 SQLite 只是一个适合移动应用或快速原型的轻量级数据库,那么你已经错过了几年来的重要发展。SQLite 持续得到积极维护,其内置功能在许多工作负载下足以媲美更重量级的数据库,并且现在还能直接在浏览器中运行。以下是一些值得了解的内容。
关键要点
- JSONB 存储提供了一种紧凑的二进制格式,解析速度比文本 JSON 更快,并且可以直接对 JSON 表达式建立索引。
- STRICT 表为 SQLite 带来了真正的类型强制约束,弥补了它与 PostgreSQL 等数据库之间长期存在的差距。
- RETURNING 子句免去了在 INSERT、UPDATE 或 DELETE 操作之后再执行 SELECT 的需要。
- 官方 SQLite WASM 构建结合 OPFS 持久化,使浏览器内驻留的数据库成为一种切实可行的架构选择。
- WAL 模式只需一条 PRAGMA 语句即可改善读写并发性能。
JSON 与 JSONB 支持:不仅仅是文本存储
SQLite 多年前就已支持 JSON 函数,但近期新增了 JSONB 支持——这是一种二进制格式,能更紧凑地存储文档,且解析速度比纯文本 JSON 更快。
当你使用 jsonb() 存储数据时,SQLite 不会在每次读取时重新解析文本。对于处理大型 JSON 负载、读多写少的工作负载来说,这一点非常关键。
CREATE TABLE events (
id INTEGER PRIMARY KEY,
payload BLOB NOT NULL -- store as JSONB
);
-- Insert using jsonb()
INSERT INTO events (payload)
VALUES (jsonb('{"user": {"id": 42}, "action": "login"}'));
-- Query with standard json_extract — works on JSONB columns too
SELECT json_extract(payload, '$.user.id') AS user_id
FROM events
WHERE json_extract(payload, '$.action') = 'login';
SQLite 的 JSON 函数能透明地接受文本 JSON 和 JSONB 两种值,因此无论存储格式如何,你都可以继续使用 json_extract() 等函数。
你还可以直接对 JSON 表达式建立索引,这使得在不反规范化 schema 的情况下,对嵌套字段的过滤变得高效:
CREATE INDEX idx_action ON events (json_extract(payload, '$.action'));
何时使用 JSONB 还是 TEXT: 当 SQLite 需要频繁处理或查询 JSON 值时,使用
BLOB+jsonb()。当你需要原样保留插入时的原始字符串时,使用TEXT。
⚠️ 版本提示: JSONB 支持是在 SQLite 3.45(2024 年 1 月)中引入的。在依赖该特性之前,请确认你的运行时版本。
SQLite STRICT 表:真正的类型强制约束
SQLite 的灵活类型系统很有用,但当某个列默默接受了错误类型时,可能会引入难以察觉的 bug。STRICT 表通过在插入时强制约束列类型解决了这一问题,其行为类似于 PostgreSQL。
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL,
age INTEGER NOT NULL
) STRICT;
尝试将 'twenty-five' 插入 age 列,SQLite 将会拒绝。STRICT 表支持五种允许的列类型:INT、INTEGER、REAL、TEXT、BLOB,外加特殊的 ANY 类型。ANY 类型可让该列重新启用 SQLite 常规的灵活行为,因此你可以在同一张表中混合使用严格列和灵活列。
⚠️ 请先确认版本: STRICT 表需要 SQLite 3.37 或更高版本。运行
SELECT sqlite_version();来确认。
RETURNING 子句:更清爽的变更查询
如果你曾经插入一行后立即查询以获取生成的 ID,RETURNING 可以省去这一次往返:
INSERT INTO orders (user_id, total)
VALUES (42, 99.99)
RETURNING id, created_at;
它适用于 INSERT、UPDATE 和 DELETE,在搭配 better-sqlite3 或 Bun 内置的 SQLite 等库进行服务端 JavaScript 开发时尤其实用。RETURNING 是在 SQLite 3.35 中加入的。
Discover how at OpenReplay.com.
SQLite WASM:在浏览器中直接运行 SQLite
SQLite 项目提供了官方的 WebAssembly 构建,可以在浏览器标签页中运行完整的 SQLite 引擎。与早先的 sql.js 不同,官方 SQLite WASM 构建支持 源私有文件系统(OPFS) API,可实现持久化、基于文件的存储,这意味着你的数据库无需服务器即可在页面刷新后依然存在。
这为 SQLite 前端开发开启了真正可行的架构方案:
- 离线优先的应用,本地查询并在稍后同步
- 客户端分析或报表工具
- 希望在不同环境下使用统一数据库抽象的 Electron 和 Tauri 应用
- 具备真实查询能力的浏览器端开发者工具
OPFS 作为 File System API 的一部分,已被 MDN 收录文档,Google 的 web.dev 指南指出它已在所有主流浏览器中得到支持。某些基于 OPFS 的 SQLite WASM 配置还要求安全上下文(HTTPS)、SharedArrayBuffer 支持,以及取决于所选 VFS 实现的相应 COOP/COEP 响应头。
WAL 模式:无需复杂配置即可获得更好的并发性
预写式日志(Write-Ahead Logging)让读取者和写入者可以并发工作而互不阻塞。对于需要并发读写、或对感知延迟敏感的应用,启用 WAL 模式通常是值得的:
PRAGMA journal_mode = WAL;
这条 PRAGMA 语句能显著提升本地优先应用、Electron 应用,以及承载真实流量的轻量级后端服务的性能。需要注意的是,WAL 模式要求数据库文件位于本地磁盘上,因为它在网络文件系统上无法可靠工作。
结语
JSONB、STRICT 表、RETURNING、带 OPFS 的 WASM 以及 WAL 模式等现代 SQLite 特性,使 SQLite 在远比其名声所暗示的更广泛的应用场景中都成为了可信的选择。该项目仍在积极开发,对于不需要大规模多写并发的工作负载,SQLite 与重量级数据库之间的差距已大幅缩小。如果你最近没有重新审视 SQLite 的能力,现在正是个好时机。
常见问题
SQLite 适合用于生产环境的 Web 应用吗?
对许多工作负载而言是适合的。SQLite 能很好地处理读取繁重的流量和中小规模的写入量,特别是在启用 WAL 模式后。它最适合单服务器部署或本地优先的应用。对于需要在多个分布式服务器上支持多个并发写入者的应用,PostgreSQL 这类客户端-服务器数据库仍然是更合适的选择。
什么时候应该选择 JSONB 而不是将 JSON 存储为 TEXT?
当 SQLite 需要频繁处理或查询 JSON 值时,请选择 JSONB,因为它避免了每次读取时的重新解析,并且存储更紧凑。当你需要原样保留原始字符串(包括空白字符和键的顺序)时,请坚持使用 TEXT,这对加密签名或审计日志等场景非常重要。
STRICT 表会破坏现有的 SQLite 数据库吗?
不会。STRICT 是按表选用的,因此现有表会继续使用 SQLite 的灵活类型系统。你可以在新的 schema 中引入 STRICT 表,或逐步迁移特定的表。在向任何 CREATE TABLE 语句添加 STRICT 关键字之前,只需确认你运行的是 SQLite 3.37 或更高版本即可。
浏览器中的 SQLite WASM 性能能否媲美原生 SQLite?
性能接近但并不完全相同。由于 WebAssembly 的开销,以及 OPFS 文件访问不如原生磁盘 I/O 直接,WASM 构建的运行速度比原生 SQLite 慢一些。对于许多中等规模的客户端工作负载,这种差异是可以接受的,但大数据集和繁重的分析查询仍可能出现明显的减速。
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Star on GitHub12k