⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.iocoder.cn/Fight/turso-sqlite/ 「芋道源码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

Turso 是一个用 Rust 重写的 SQLite 兼容数据库,仓库现在两万四千多 Star,频繁出现在 GitHub Trending 上。它把自己做成了一台虚拟机,SQLite 只是跑在上面的一门语言,这个设计决定了它后面所有能力的形状。

一部虚拟机,两个 SQL 前端

它想成为数据库界的 LLVM。像 SQLite 那样,它把 SQL 编译成一台叫 VDBE 的虚拟机的字节码,再执行这段字节码。SQLite 是第一个也是最主要的前端,Postgres 是新增的实验性前端,带自己的方言和线协议。前端可以换,下面那套存储、并发、查询编译器和虚拟机是同一套。

tursodatabase/turso 仓库首页,Star 24.4k

这台虚拟机有多通用,仓库里挂了一个例子,有人用同一套 VDBE 跑起来一局 Doom。一个数据库的字节码引擎能跑游戏,这件事本身就说明了「一台核心、多个前端」留出的空间。

仓库是 MIT 协议,默认分支 main,2023 年 8 月建库,到现在两万四千多 Star、一千三百多个 Fork,git 分支已经有 770 个。首页简介栏里写的正是那句自我定位,Star 数和许可证就在同一屏,你可以自己核。

兼容到哪一步,迁移前先查那份清单

兼容不是一句口号。官方有一份 COMPAT.md 逐条跟踪与 SQLite 的差异,当前跟踪的是 SQLite 3.50.4,验证方式是拿同一批查询分别跑两边做差分测试,最终目标是跑通 SQLite 官方的 TCL 测试套件。文件格式完全支持,现有的库文件可以直接打开,SQL 方言和 C API 还只是部分支持。

拎着 SQLite 文件过 Turso 这道门

图里门框上挂着三个问号,触发器、视图、VACUUM,这几个现在都有了明确答案。触发器、视图、VACUUM INTO 和保存点在清单里已经标成支持。

要留意的是另外几条。文本必须是合法的 UTF-8,SQLite 允许文本列存任意字节,Turso 在把不合法的字节转成文本时会换成 U+FFFD 这个替换字符,所以库里本来就有脏字节的场景要当心。同一条连接不跑多线程,默认也不支持多进程访问,这两条直接决定你怎么部署它。视图上的 INSTEAD OF 触发器不支持,原地 VACUUM 和 WITHOUT ROWID 表需要打开实验开关才能用。

迁移前值得做两件事,一件是拿真实的库和真实的慢查询在这上面跑一遍,另一件是确认你的代码没有依赖上面那几条。

写操作不再排队,但要看清前提

SQLite 最常被抱怨的地方是写操作串行化,多个线程同时写就得排队。Turso 用 MVCC 换掉这条限制,写法是在事务前加 BEGIN CONCURRENT,多个写事务同时进行,提交时检测冲突,撞上的那笔回滚。

排队写与多版本并行写的对照

它有两种日志模式,默认是 wal,另一种是 mvcc。官方手册给 mvcc 加了一句很直白的标注,暂不建议用于关键数据。三条具体限制是,wal_checkpoint(TRUNCATE) 会同时阻塞读写,WITHOUT ROWID 表上的索引还不支持,用 mvcc 写过的库再用普通模式打开得先 checkpoint 一次。旧的 delete、truncate、persist、memory、off 会被识别,但切换过去会报错。

也就是说这一块现在能省掉排队,还没有到可以放心承担关键写入的程度,值得先在读多写少、或者能容忍重试的场景里试。

向量搜索进了内核,四类向量四种距离

做 AI 应用要用向量检索,通常的做法是外面再挂一个向量库。Turso 把这件事收进了内核,支持四类向量表示。稠密向量有 vector32 和 vector64 两档精度,稀疏向量 vector32_sparse 只存非零值和下标,8 位的 vector8 按最小最大值做线性量化,1 位的 vector1bit 把每个维度压成一个比特。

距离函数有四个。vector_distance_cos 算余弦距离,作用在 1 位向量上退化成汉明距离。vector_distance_l2 是欧氏距离,对 1 位向量直接报错。

vector_distance_dot 返回负内积,取最小值就是最大内积搜索。vector_distance_jaccard 是加权 Jaccard 距离,在 1 位向量上变成二值 Jaccard。参与比较的两个向量必须是同一种类型、同一个维度。

边界也要说清楚。现在能用的是精确检索,近似检索需要的向量索引还在路线图上。所谓精确,就是拿查询向量逐条比距离。所以它替你省掉的是多维护一个向量服务这件运维上的事,规模上去以后的召回速度还是得靠专用向量库。

剩下这些能力,实验性的还不少

变更数据捕获能实时抓数据库的变更推到消息队列或者外部系统,做同步、审计和实时分析不用再自己轮询,这一项已经进了正式能力列表。全文搜索集成了 Rust 写的 Tantivy,建索引用 CREATE INDEX ... USING fts,不用再外接 Elasticsearch,不过它还留在实验分组里。

另外几项也标着实验。静态加密要开 --experimental-encryption,用 PRAGMA cipher 选 AEGIS-256 或者 AES-256-GCM,密钥用 PRAGMA hexkey 传 32 字节,要重开一个已经加密的库必须走 URI 形式把参数带上。多进程 WAL 协调靠一个 .tshm 共享内存侧车,让多个进程能同时读。DBSP 那套增量计算用来做增量视图维护和查询订阅。Postgres 前端同样标着实验。

已经转正的一项容易被忽略,扩展的 ALTER 支持和更快的 schema 变更进了正式列表。Linux 上的异步 I/O 走 io_uring,读写不阻塞线程,对无服务器和边缘场景的意义比较大。

浏览器这一侧走 WebAssembly,数据库落在 OPFS 里,主线程把 IO 请求交给 Web Worker,再用同步接口和文件系统打交道。

浏览器里的主线程、Worker 与 OPFS 调用关系

上手只有几条命令

官方给了命令行和六种语言的 SDK,最短的一条路是先把命令行装上。

curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/tursodatabase/turso/releases/latest/download/turso_cli-installer.sh | sh

装完敲 tursodb 就进交互式 shell,建表和插数据都能直接开。

装 JavaScript SDK

前端和后端常用的 JavaScript SDK 走 npm,包名是 @tursodatabase/database。

npm install @tursodatabase/database

接上数据库,跑通建表增删查

新建一个 JS 文件,连上已有的 SQLite 库文件或者新建一个,建表、插数据、查回来一次跑通。

import { connect } from '@tursodatabase/database';

const db = await connect('mydb.db');

await db.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT
)
`);

const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
insert.run('Alice', 'alice@example.com');

const users = db.prepare('SELECT * FROM users').all();
console.log(users);

跑完这一遍能确认两件事,现有的库文件确实能被直接打开,prepare 和 exec 这套接口跟你在 SQLite 上的写法也基本一致。

换语言和 MCP 接入

换语言要装的包不一样,用法对照着看差不多。Rust 是 cargo add turso,Python 是 uv pip install pyturso,Go 是 go get turso.tech/database/tursogo,Java 走 JDBC,.NET 用 TursoConnection。

cargo add turso
uv pip install pyturso
go get turso.tech/database/tursogo

向量检索这边要先装对应扩展,再建向量索引、插入向量数据,最后算距离拿到排序结果,四步走完就能用。

还有一条更省事的路。命令行自带一个 MCP 服务器模式,加上 --mcp 启动之后,编辑器里的 AI 助手就能直接读表和查询,九个工具覆盖了打开数据库、看当前库、列表、看表结构、查询、增删改和改表结构。

tursodb ./data/app.db --mcp

托管侧和嵌入式副本是另一条线

上面讲的都是那个 MIT 协议的开源引擎,自己编译自己跑都行。Turso 还有商业的那一条,托管服务把库文件切成 128KB 的段放进对象存储,靠边缘节点就近服务,支持数据库分支和即时复制。

Turso Cloud 控制台里的活动指标与分支列表

另一块是嵌入式副本。应用发起写操作时委派给远程库,读操作走本地那份副本,副本按需同步回来,移动端、IoT 设备和离线应用是它主打的场景。

嵌入式副本里应用、本地副本与远程库的读写流向

这两块都依赖托管侧账号,和开源引擎是两条独立的线,自己用引擎不需要碰它们。

什么时候值得换

值得试的情况有几类。你在用 SQLite,被并发写卡住了,想把写锁这条限制换掉。你要做 AI 应用,需要向量检索,又不想多维护一个服务。你在做边缘、无服务器或者浏览器里的应用,需要进程内、低延迟还能异步的存储。

先别急着换的情况也清楚。你要的是 1.0 级别的稳定性和完整的 SQLite 兼容。你的代码依赖多线程写同一个连接,或者要多进程访问同一个库。你依赖 WITHOUT ROWID 表上的索引,或者必须用原地 VACUUM。你打算直接在关键数据上开 mvcc 模式。

真要迁移,官方 FAQ 自己给的提醒是按对待任何数据库的方式来,独立备份不能省。它已经在多家组织的生产环境里跑着,只是还没到 1.0,当前版本是 0.7。仓库在 https://github.com/tursodatabase/turso

文章目录
  1. 1. 一部虚拟机,两个 SQL 前端
  2. 2. 兼容到哪一步,迁移前先查那份清单
  3. 3. 写操作不再排队,但要看清前提
  4. 4. 向量搜索进了内核,四类向量四种距离
  5. 5. 剩下这些能力,实验性的还不少
  6. 6. 上手只有几条命令
    1. 6.1. 装 JavaScript SDK
    2. 6.2. 接上数据库,跑通建表增删查
  7. 7. 换语言和 MCP 接入
  8. 8. 托管侧和嵌入式副本是另一条线
  9. 9. 什么时候值得换