ARTICLE · 1177737
SQLite 3.54.0的源码里多了个官方向量检索扩展,发布说明提了0次

SQLite的发布历史页上,vec1这个词出现了0次。
vec1是个向量检索扩展。向量检索,就是给每条数据配一串数字当坐标,查的时候不比字面,比谁的坐标离得最近。它由SQLite开发组自己写。官方文档页挂在sqlite.org上,源码躺在10月9日发布的3.54.0源码包里。可那份发布说明从头到尾没提过它。
如果你正在用SQLite,先把预期摆正:你手上那份大概率没有这个能力,升级也不会自己长出来,得自己动手编。
这事最早是日本开发者mattn在Zenn上写出来的,标题说向量检索扩展vec1“来到了SQLite本体”。“本体”这两个字值得较真,所以我把官方的源码包下下来翻了一遍。

它到底算不算进了SQLite本体?
我下了两个版本的完整源码包对着看。上一个版本3.53.4里搜不到vec1。3.54.0里有一个ext/vec1目录,主文件vec1.c一万两千多行,外加51个测试文件、将近6900行测试。源码包自带的签入信息写着3.54.0的时间是10月9日。
但再往下一层,结论就变了。大多数人用的SQLite不是整棵源码树,是amalgamation。官方把整个引擎合并成了一个C文件sqlite3.c,9MB多,手机App、浏览器、各种桌面软件嵌进去的就是它。我在3.54.0的这个文件里搜vec1,命中0次。
源码包里那份构建规则文件main.mk把话说得更死。注释写着:vec1不属于amalgamation,也不属于任何分发包,只有显式要求才会构建。可加载扩展的意思是,它编出来是个单独的动态库文件,运行时由数据库临时加载进来。
这么一核,“本体”一半对一半不对。源码确实进了官方源码树,还跟着正式版一起发了出去。但它不是一个编译开关就能打开的内置功能。JSON和FTS5那批扩展是随amalgamation一起走的,vec1没这待遇。FTS5就是SQLite自带的全文检索。
导入的日期和提交人我只能按mattn原文记:9月30日,Dan Kennedy,也就是写FTS5的那位。官方的提交记录我没对上。源码文件头部的日期是2026年2月4日,这东西写了大半年。
它跟全文检索解决的是同一件事吗?
不是。FTS5对的是字面:你搜“笔记本”,它找正文里有这几个字的。向量检索对的是坐标远近。所以一条写着“性价比高的笔电”的记录也能被捞出来,前提是你已经用别的办法把文字变成了那串数字。vec1不管变数字这一步,它只负责把数字收好、比快。
它的用法因此比很多人以为的宽。mattn那篇里做了个按读音查词的小工具。他把22万个日语词的读音转成罗马字,切成碎片,再压成一串数字存进vec1。输入“バナーナ”能查出“バナナ”,输入hamburger能查出“ハンバーガー”。全程没动用任何模型,因为对vec1来说,一串数字就是一串数字。

是暴力扫一遍,还是建索引?
两套都有,这个差别决定了它能撑多少数据。
默认不建索引,逐条算距离,结果精确。还有一档叫flat,向量不再一行存一条,而是打包成大块数据存,照样扫全表,官方说这样能快一倍。官方用户手册给的分界线很明确:要求结果精确的,或者向量少于5000条的,就用这两档。
数据量上来才走近似检索。先拿一批有代表性的向量训练出一个模型,把所有向量按远近分进若干个桶。查的时候只翻离查询点最近的那几个桶,默认只翻5%。这就放弃了“保证找到最近的”,换速度和内存。
官方跑分页上有组数字。100万条128维向量,用16个核训练只要1秒多,建索引不到1秒。查的时候单线程每秒能跑4000多次,要10个最近的,有九成二确实是真正最近的那批。手册里还压了一句很重的话:近似模式下“重排”通常是必须的。重排就是先多要100个回来,用没压缩过的真向量重算距离,再挑出最好的10个。不做这步,手册的原话是结果会“相当难看”。
距离度量只有两种,欧氏距离和余弦距离。内积还躺在路线图上,没做。我照官方那页的说明把扩展编了一遍,跑了它给的四维例子,返回的距离是0.02。它给的是平方距离,不是距离本身。这点参考手册里写了,但一眼看过去容易漏。

维度能开到多大?
这条官方文档没写。参考手册只说向量是32位浮点数打包成的二进制块,同一张表里长度必须一致,不许出现无穷大和非数值。上限一个字都没提。
我在vec1.c里把那个常量找出来了:最小2维,最大4096维。又自己存了一遍,4096维进得去,4097维直接报错说向量尺寸不合法。常见的768维、1024维、1536维、3072维都在范围内,再往上就不行。
还有个容易栽的地方,手册明写了。不同机器存浮点数的字节顺序可能不一样,模型和库不能直接搬到字节顺序不同的机器上用。
自带一个能力,和装个扩展,差在哪?
它的用法是一个文件、零配置、随便嵌,内置和外挂的差距在这种场景里被放大了。
内置是编译时就在里面,不多一个文件,不需要运行时去加载外部动态库。而相当多的嵌入式环境和移动App不允许运行时加载扩展,有的是系统限制,有的是安全审计那关过不去。
vec1现在是外挂这一种。你要么单独编一份动态库出来运行时加载,要么把vec1.c直接编进自己的程序。前一条路在不少App的分发环境里走不通。“进了源码树”和“进了amalgamation”之间,隔的就是这道坎。
现在能用上吗?
能,条件是完整源码树加自己构建一次,官方给的步骤就两步。我在一台Mac上照着做了,编出来的扩展不到200KB。加载后问它版本,返回的是“version 0.8 (NEON, multi-threaded)”。NEON是ARM芯片上一条指令同时算多个数的那套加速指令,它自己认出来用上了。x86上对应的是AVX2,官方的配置程序会自动编两份,运行时按CPU挑。顺带一个小坑,官方页面特意注明了,Mac上要构建的目标文件后缀是dylib不是so。
用不上的情况更常见:语言自带的SQLite(Python、Node那些)、系统里装的那份、App里嵌的amalgamation。这些都没有vec1,升到更高版本也不会有,因为它根本不在那个文件里。
想现在就上的,替代品是Alex Garcia做的第三方扩展sqlite-vec。它和vec1是两个独立项目,别混为一谈。作者不同,虚拟表的名字也不同,一个叫vec0一个叫vec1。虚拟表就是用起来像普通表、底层读写由扩展自己接管的那种表。sqlite-vec最大的优势是Python、Node、Ruby、Go、Rust都有现成安装包,装完就能用。功能上有个实在的差别,按它自己文档的说法,它做的是暴力扫描,没有需要训练的近似索引,vec1两套都有。它自己也标着还没到1.0版。
vec1自己的路线图上,排第一条的是“更多更好的测试”。后面才是换一种图结构的索引、支持更省空间的8位和16位向量这些。版本号停在0.8,确实还不到往生产环境里放的时候。
真正让我没想通的是另一件事。官方把vec1的说明页、用户手册、参考手册、跑分页四个页面都做齐了,10月1日还更新过一轮。源码也跟着正式版发了出去。可SQLite的发布说明里它出现0次,文档索引页上也找不到入口。真正写着文档地址的地方是vec1.c的文件头部。构建规则里的注释说它“不属于任何分发包”,而它人就在3.54.0的源码包里。这两句话互相对不上,对不上的原因我没找到官方说法。















































































