你可能错过的现代 SQLite 特性
如果你仍然认为 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 能很好地处理读取繁重的流量和中小规模的写入量,特别是在启用 WAL 模式后。它最适合单服务器部署或本地优先的应用。对于需要在多个分布式服务器上支持多个并发写入者的应用,PostgreSQL 这类客户端-服务器数据库仍然是更合适的选择。
当 SQLite 需要频繁处理或查询 JSON 值时,请选择 JSONB,因为它避免了每次读取时的重新解析,并且存储更紧凑。当你需要原样保留原始字符串(包括空白字符和键的顺序)时,请坚持使用 TEXT,这对加密签名或审计日志等场景非常重要。
不会。STRICT 是按表选用的,因此现有表会继续使用 SQLite 的灵活类型系统。你可以在新的 schema 中引入 STRICT 表,或逐步迁移特定的表。在向任何 CREATE TABLE 语句添加 STRICT 关键字之前,只需确认你运行的是 SQLite 3.37 或更高版本即可。
性能接近但并不完全相同。由于 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.
Check our GitHub repo and join the thousands of developers in our community.