镜像 pgvector/pgvector:pg16 能力对齐 0.8.x:两种 ANN,加上 0.8 起的 iterative scan。
官方原话可以记成两句:默认精确、完美召回;一旦加上近似索引,同一条 SQL 的结果会变。HNSW 速度–召回更好、构建更慢更吃内存;IVFFlat 反过来。
一句话: pgvector 没有第三种能「又快又全准」的向量索引。在线 Top-K 用 HNSW;要「阈值以上一张不漏」,只能精确扫(或先把身份落成标量再走 B-tree)。
先分清三层
算法、列类型、距离算子是三件事,建索引时不要混在一起。
① 检索算法(索引方法,只有这些)
精确扫(无向量索引) | HNSW | IVFFlat
② 向量类型(列怎么存)
vector(512) float32
halfvec float16
bit 二值
sparsevec 稀疏(仅 HNSW 能建索引)
③ 距离(operator class,每种索引要单独建)
<=> 余弦 <-> L2 <#> 内积 <+> L1(仅 HNSW)
<~> Hamming / <%> Jaccard(bit)
建索引必须写成 USING hnsw (col vector_cosine_ops) 这种。换距离 = 再建一个索引,不是新算法。
对照
| 精确扫(无 ANN) | HNSW | IVFFlat | |
|---|---|---|---|
| 本质 | 逐条算距离 | 分层小世界图 | k-means 切桶,只探近的桶 |
| Top-K | 精确 | 近似 | 近似 |
| 阈值以上全部 | 精确 | 不保证 | 不保证(probes=lists 时约等于精确,规划器往往改走精确扫) |
| 构建 | 无 | 慢,吃内存;空表就能建 | 快、省内存;必须先有数据做 k-means |
| 查询 | O(N),最慢但全准 | 同召回下通常比 IVF 快 | 同资源下召回/延迟一般不如 HNSW |
| 插入 | 普通 heap | 图要维护,持续写入会胀 | 新点塞进旧质心,数据分布变了召回掉,要重建 |
| 核心旋钮 | 无 | 构建 m(默认 16)、ef_construction(64);查询 ef_search(默认 40,上限 1000) |
构建 lists;查询 probes(默认 1) |
| 维度上限 | vector 存 16000 维;索引(HNSW/IVF)只到 2000 |
halfvec 到 4000,bit 到 64000,sparsevec 仅 HNSW(最多 1000 个非零) |
无 sparsevec / L1 / Jaccard;Hamming(bit)可以 |
| 主流规模 | < 10 万 常驻在线;一天分区 50 万~百万也能做离线/秒级查询 | 10 万~千万 在线 Top-K;再大靠分区或量化 | 100 万~千万、偏静态、能接受重建 |
| 主流用法 | 底库、评测 ground truth、范围全量 | RAG / 以图搜人 / GetTracks | 一次性灌库、内存紧、召回要求一般 |
各自怎么用
1. 精确扫
完整到访、评测、「阈值以上一张不漏」该用这一档。不要建 HNSW;高选择性的 WHERE 先走 B-tree 裁子集,再在子集上精确算。
-- 先裁子集,再精确扫
CREATE INDEX ON t_ai_face_trajectories_2026_09_18 (capture_time);
SELECT id, 1 - (face_feature <=> $q) AS sim
FROM t_ai_face_trajectories_2026_09_18
WHERE capture_time >= $start AND capture_time < $end
AND 1 - (face_feature <=> $q) >= $threshold;
如果规划器硬要走向量索引,再临时关掉它(仅本事务):
BEGIN;
SET LOCAL enable_indexscan = off;
-- 上面的 SELECT
COMMIT;
- 优点: Top-K 和全部返回都准;实现简单。
- 缺点: 跟数据量线性;512 维一天约 1GB 向量,热缓存秒级,冷盘可十几秒。
- 数据量: 底库 1 万这一档很快(Faiss Flat 也是这个理由,常 < 10ms);单日人脸 55 万~140 万能扛;全表几百万以上不要当在线接口。
- 主流: 小库 exact;大库先用时间 / 租户分区把 N 裁小再扫。pgvector 文档也写:选择性高的
WHERE先走 B-tree,子集上精确比 ANN 更合适。
2. HNSW
在线只要最近邻时的默认选项。空表可建,适合持续 INSERT。
CREATE INDEX ON t_ai_face_trajectories
USING hnsw (face_feature vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
SET LOCAL hnsw.ef_search = 100; -- 至少 ≥ LIMIT,需要更高召回再往上调
SELECT ... ORDER BY face_feature <=> $q LIMIT 100;
- 优点: 在线 Top-K 的默认选项;空表可建;同召回下比 IVF 快。
- 缺点: 索引大(人脸轨迹大约 ~2.7GB/天);构建 / REINDEX 要很大
maintenance_work_mem;ef_search只决定本查询的动态候选数,不是召回保证;过滤在扫完之后做,带capture_time/ 距离阈值会漏或拖死;DELETE 后图膨胀。 - 数据量: 单索引几百万到千万常见。再往上(亿级)一般要分区、halfvec、或专用向量库。两天 280 万行时 HNSW 已经 5.75GB,才改成按天分区。
- 主流: RAG、推荐、以图搜图、GetTracks 这种只要最近邻。0.8 的
hnsw.iterative_scan是为了「LIMIT + WHERE 滤掉太多」继续往下探,不是范围查询保证全准,还有max_scan_tuples上限。
3. IVFFlat
适合「先灌满再查」。新项目默认选 HNSW,IVF 是明确要省构建 / 内存时才用。
-- 官方起点:≤100 万 lists ≈ rows/1000;>100 万 lists ≈ sqrt(rows)
-- probes 起点 ≈ sqrt(lists)
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 1000);
SET LOCAL ivfflat.probes = 32;
- 优点: 构建快、索引小;适合先灌满再查。
- 缺点: 空表 / 数据太少建出来会很差;质心不随写入更新,分布变了要重建;默认
probes=1召回很低;速度–召回通常不如 HNSW。不支持 sparsevec、L1、Jaccard;Hamming(bit)在 IVF 上能建(bit_hamming_ops)。 - 数据量: 百万~千万、更新不频繁。
probes = lists理论上穷尽,文档写此时规划器不会用这个索引,退回精确扫。 - 主流: 早期 pgvector(0.5 以前只有 IVF)的遗留;批量 embedding 库;内存比延迟更紧的场景。
不是索引、但常被当成「第四种」
| 东西 | 是什么 | 干什么 |
|---|---|---|
| halfvec 索引 | 对 float32 列建 USING hnsw ((col::halfvec(512)) halfvec_cosine_ops) |
索引减半、可到 4000 维;召回略降,常再精确重排 |
| bit / 二值量化 | 列或表达式变成 bit,Hamming | 极致压缩、粗筛;人脸 512 维一般不靠它当主检索 |
| iterative_scan | 查询参数,0.8+ | ANN 被 WHERE 滤光后继续探;有上限,不能当全量范围索引 |
| 分区 / 部分索引 | 日分区、WHERE camera_id=... |
先裁 N,再 ANN 或精确扫。人脸副表已经按天分区 |
| pgvectorscale DiskANN | Timescale 另一个扩展 | 不是 pgvector 自带 |
怎么选
N 小、必须全准、或「阈值以上一张不漏」
→ 精确扫(可加日分区)
→ 完整到访、评测、Faiss 底库那档
N 大、只要最近的 K 个、持续写入
→ HNSW + LIMIT ≤ ef_search
→ GetTracks / 快速寻人(现状)
N 大、几乎只读、内存紧、能接受定期 REINDEX
→ IVFFlat
→ 没必要为「全部返回」去用
在线 Top-K 用 HNSW;要 MySQL 那种全部返回,只能精确扫。两条路径不要指望用同一种 ANN 兼顾。