实测 5 个向量检索库:谁最省内存?谁跑得最快?
实测 5 个向量检索库:谁最省内存?谁跑得最快?
一次把 FAISS、TurboVec、USearch、Voyager 全部拉上 WSL 实测,答案有点意外。
两个月前我想在笔记本上跑一个本地 RAG,10 万条文档的 embedding 存成 float32 要吃掉将近 1GB 内存。这还是什么都没干,光存向量。
然后就看到了 TurboVec——宣传说 10M 向量从 31GB 压到 4GB,16 倍压缩,还比 FAISS 快。
听起来太好以至于不太像真的。所以我干脆把目前主流的几个向量检索库全部装上一遍,同一台机器、同一个数据集、同一个指标,从头跑到尾。
参赛选手
| 库 | 作者 | 核心卖点 |
|---|---|---|
| FAISS | Meta | 老大哥,40K⭐,什么都能做 |
| TurboVec | Ryan Codrai (个人) | Google TurboQuant 算法,零训练,2-4 bit 量化 |
| USearch | Ash Vardanian / Unum | HNSW 纯速度,10+ 语言绑定 |
| Voyager | Spotify | 生产验证的 HNSW,E4M3 8-bit 存储 |
LanceDB 这次没跑——它是完整的列式数据库(ACID、多模态、时间旅行),不是纯向量索引。跟上面四个不在一个赛道。后文简单说区别。
测试环境
- 机器:WSL2,16 核,32GB RAM
- 数据集:随机生成 d=1024 归一化向量(模拟 BGE-M3 embedding)
- 规模:10K / 100K 向量
- 指标:搜索 100 条查询耗时、内存占用、Recall@10
- Ground truth:FAISS IndexFlatIP(float32 精确搜索)
10K 向量:小规模全貌
| 库 | 搜索100条 | 内存 | Recall@10 | 训练 |
|---|---|---|---|---|
| FAISS FlatIP (基准) | 41ms | 152MB | 1.000 | 0s |
| TurboVec 4-bit | 40ms | 19MB | 0.855 | 0s |
| TurboVec 2-bit | 24ms | 22MB | 0.565 | 0s |
| FAISS PQ 8-bit | 44ms | 114MB | 0.781 | 16s |
| FAISS IVFPQ | 5.9ms | 122MB | 0.168 | 25s |
| FAISS HNSW IP | 15ms | 168MB | 0.563 | 2s |
| USearch HNSW f32 | 11ms | 42MB | 0.286 | 0s |
| USearch HNSW bf16 | 5.6ms | 21MB | 0.323 | 0s |
| Voyager HNSW f32 | 2.2ms | 41MB | 0.057 | 0s |
几个反直觉的发现:
1. TurboVec 2-bit 比 FAISS Flat 还快。 24ms vs 41ms。按理说量化后要多一步解压,反而更快——因为数据更紧凑,CPU cache 命中率高出一大截。
2. 内存压缩不是 16 倍,是 8 倍。 TurboVec 4-bit 占用 19MB,FAISS Flat 152MB。宣传的"16 倍"是单向量层面的理论值(6144 字节 → 384 字节),实际索引有开销。
3. HNSW 快但 Recall 惨。 这不是 HNSW 算法的问题,是默认参数太低。Voyager 2.2ms 但 R@10 只有 0.057——大部分时间在找错的东西。HNSW 的 efSearch 参数(搜索宽度)必须调大,但没调的话就是这么快+这么不准。
100K 向量:谁扛得住量?
| 库 | 搜索100条 | 内存 | Recall@10 | 训练 |
|---|---|---|---|---|
| FAISS FlatIP (基准) | 322ms | 959MB | 1.000 | 0s |
| TurboVec 4-bit | 401ms | 120MB | 0.816 | 0s |
| TurboVec 2-bit | 230ms | 57MB | 0.467 | 0s |
| FAISS PQ 8-bit | 308ms | 618MB | 0.722 | 16s |
| FAISS IVFPQ | 14.6ms | 607MB | 0.072 | 18s |
(USearch / Voyager 在 100K 规模上的数据因 benchmark 进程被中断未能记录,但从 10K 的趋势看,速度会有优势但 Recall 需要参数调优。)
到 100K 规模差距拉开了:
- 内存:TurboVec 2-bit 57MB vs FAISS Flat 959MB = 1/17。注意这不是绝对值 57MB vs 959MB,而是如果你要在内存里跑 100K 向量的 RAG,TurboVec 只用 FAISS 1/17 的内存。
- Recall 退化:TurboVec 2-bit 从 10K 的 0.565 掉到 100K 的 0.467——因为 2-bit 的信息损失在更大空间里更致命。4-bit 只从 0.855 掉到 0.816,很稳。
- FAISS IVFPQ 的 Recall 崩了:0.072 基本等于瞎猜。这不是 FAISS 的问题,是我用的 nprobe=8 太小。调到 32 会好很多,但也会更慢。训练了 18 秒的结果就是这个——参数没调好,白训练。
五个库的真实使用体验
TurboVec 的杀手锏不是速度,是零训练。
1from turbovec import TurboQuantIndex
2
3# 不需要 train(),不需要调参
4idx = TurboQuantIndex(dim=1024, bit_width=4)
5idx.add(vectors)
6scores, indices = idx.search(query, k=10)
这就是全部。FAISS PQ 要先跑 k-means 训练码本,USearch 要调 HNSW 的 M/efConstruction/efSearch。TurboVec 什么都不用。新增数据不需要重建任何东西。
「零训练」对三个场景是刚需:
- 边缘设备:没有 GPU、内存小,没办法跑 k-means
- 动态语料:每天新增文档,数据分布随时间漂移。FAISS PQ 的码本会过时,需要重训。TurboVec 不用
- 快速原型:五分钟从零到能跑,不需要操心训练参数
USearch 在纯 HNSW 速度上是冠军。
10K 向量上 f32 HNSW 11ms,bf16 5.6ms。而且它支持 f32/f16/bf16/i8/u8/e4m3/b1 十种精度,uint40_t 的边压缩也省 37.5% 的内存。作者 Ash Vardanian 写了 2000 多个 SIMD kernel(他的 NumKong 库),从 AVX2 到 NEON 到 SVE 全覆盖。
缺点是默认参数下的 Recall 偏低。需要你自己调,但接口很友好。
Voyager:生产级但只适合一类人。
Spotify 内部用了快四年,Java 和 Python 双语言支持,索引文件跨语言互通。如果你的团队有 Java 服务端 + Python 数据科学家,Voyager 是唯一一个两边都能直接读同一个索引文件的。
FAISS:什么都有,就是有点重。
40K star 不是白来的。GPU 加速、IVF、HNSW、PQ、SQ、OPQ……你能想到的索引类型它都有。但 84K 行 C++、SWIG 生成的 Python 绑定(升级时经常炸)、改了数据就要重建索引——这些都是真实的摩擦成本。
选型指南
1你的向量数量 < 50万?
2 ├─ 内存紧张 → TurboVec 4-bit(零训练,120MB 存 100K 向量)
3 ├─ 速度第一 → USearch bf16(5.6ms/100q @10K)
4 └─ 精确度要求高 → FAISS FlatIP(recall=1.0)
5
6你的向量数量 50万-1000万?
7 ├─ 需要零运维 → TurboVec 还是能用(线性扫描,但对 SIMD 友好的规模)
8 ├─ 追求极致 QPS → USearch f32/bf16 HNSW
9 └─ 需要 GPU → FAISS(唯一选择)
10
11你的向量 > 1000万?
12 ├─ 纯搜索速度 → FAISS IVFPQ(调好 nprobe)
13 └─ 需要持久化+多模态 → LanceDB(不是纯索引,是数据库)
14
15你是 Java 团队 → Voyager
16你是嵌入式/边缘 → TurboVec
17你是快速原型 → TurboVec
18你什么都要 → FAISS(准备好调参时间)
那些宣传没告诉你的事
"16 倍压缩"是单向量层面的,不是总体。 单向量 float32 6144 字节 → 2-bit 384 字节 = 16 倍。但实际索引有开销(元数据、旋转矩阵缓存、查询结构),我的实测是 10K 规模 8 倍,100K 规模 17 倍(57MB vs 959MB)。宣传不算假,但"省 16 倍内存"的说法不准确。
TurboVec 没有索引结构。 它做的是全量暴力扫描,靠 SIMD 指令把每个向量算一遍。10 万向量线扫 230ms 还不错,但 100 万向量就是 2.3 秒——这是 O(N) 的宿命。HNSW 在 100 万向量下是 O(log N),估计 30-50ms 就够了。数据规模大了一定要换 HNSW/IVF。
HNSW 默认参数基本不能用。 Voyager 2.2ms 但 Recall 只有 0.057,USearch 5.6ms 但 Recall 0.323。这些库并不是"不好",而是默认值太保守。如果你看 benchmark 说"比 FAISS 快 10 倍",大概率是牺牲了 Recall 换来的。调整 efSearch 到 128-256 能让 Recall 到 0.95+,但速度会慢好几倍。
FAISS 的 PQ 需要训练,训练好的码本在数据分布变了之后就没用了。 如果你每天都在加新文档,embeddings 的分布会漂移。要么定期重训(需要攒够 10 万条再跑一次 k-means),要么接受 Recall 逐渐下降。TurboVec 在这个场景下是唯一不需要操心这件事的。
总结
三个数字记住就行:
- TurboVec 省 17 倍内存(100K 向量 57MB vs 959MB),零训练即开即用
- USearch bf16 在 HNSW 上最快(5.6ms/100q @10K),但需要调参
- FAISS 是唯一有 GPU 加速的,也是生态最大的
我自己的选择:笔记本上的本地 RAG 用 TurboVec 4-bit——120MB 存 100K 文档的 embedding,完全够用。生产环境用 USearch bf16。
不是替代,是拼图。每个库有它最擅长的坑位。
数据来源:WSL2, 16核 CPU, d=1024 归一化向量, 10K/100K 规模。2026年6月9日实测。