Chapter 05
选型与前沿
前四章把 pgvector 的内核拆透了:第 1 章是排序契约(向量索引只服务 ORDER BY 距离 LIMIT k),第 2 章是 HNSW 怎么建、maintenance_work_mem 的构建悬崖,第 3 章是 MVCC churn 让召回腐烂、要 vacuum/REINDEX 收尾,第 4 章是带 WHERE 过滤的四条路。这一章退后一步看全景:pgvector 本身已停在点版本,真正的创新发生在它周围——把 DiskANN、ScaNN、量化阶梯讲成可操作的工程知识,最后落到一张"何时用谁"的决策树。
本章你将建立的判断
- pgvector 的甜点区是诚实的:数据已在 Postgres、≲10M 向量、要事务一致性、要和关系字段一起过滤——这正是前四章那条多租户 SQL 的场景。
- 越过这条线,创新在 pgvector 之外:pgvectorscale 的 StreamingDiskANN 把"图必须装进内存"的硬约束(第 2 章的构建悬崖)改成"压缩副本在内存、全精度在 SSD"。
- 量化是一架阶梯:
vectorfp32 →halfvecfp16 → 二值bit/ SBQ / RaBitQ,索引体积从 4B/维 砍到 0.125B/维,而 rescore 兜底把召回损失压在 1–2% 内。 - 连 Google 的 AlloyDB 都没选 HNSW,而是 ScaNN——这是给"HNSW 是唯一答案"这个 2024 年直觉的一记纠正。
前四章都站在一条 SQL 里面往下看零件。这一章把镜头拉远:同样这条多租户 RAG 查询,当向量数从 100 万涨到 1 亿、当 churn 高到 vacuum 追不上、当向量延迟变成热路径的瓶颈,该不该继续用 pgvector,又该换成什么。先把"什么稳定、什么在变、什么已过时"这条时间线讲清楚,再逐一拆 pgvector 周边的三条技术路线,最后给一棵能照着走的决策树。
稳定、可照学的内核:pgvector 的类型系统(vector / halfvec / sparsevec / bit)、HNSW 默认索引、binary_quantize()、0.8.0 的 iterative scan——这些是前四章的地基,不会变。最新版 0.8.2(2026-02,支持 PG18),再往上没有 0.9 / 1.0:pgvector 已经把"在 Postgres 里做向量检索"这件事做到了点版本维护阶段。
正在快速变化(近 6–18 月):扩展层在 pgvector 周围长出三条新路线——pgvectorscale(StreamingDiskANN + SBQ)、VectorChord(RaBitQ)、AlloyDB ScaNN。它们解决的都是同一个 pgvector 暂时没解的问题:上亿向量时把全精度图压下内存、把构建成本砍一个数量级。这一节就是教它们的机制。
已被取代,别再按旧法选型:① IVFFlat 作主力 → HNSW(IVFFlat 退居 legacy);② 裸 float32 全维存储 → halfvec / 量化 + rescore;③ hybrid 检索的词法腿用 ts_rank → Postgres 原生 BM25(ParadeDB pg_search / Tiger pg_textsearch);④ "pgvector 撑不过几百万向量" 这句 2023 年的论断 → 早已过时,单库千万级是常规操作,pgvectorscale 把上限推到 5000 万–亿级。
5.1pgvector 的边界,与接力者 pgvectorscale
pgvector 把内核做到了点版本维护阶段(最新 0.8.2);真正把规模上限往上推的,是它周围的扩展——首先是 Timescale(现 Tiger Data)的 pgvectorscale。
第 2 章的构建悬崖说过:HNSW 图必须基本装进 maintenance_work_mem,否则建索引退化成磁盘上的随机访问,慢到像挂死;查询期同样要图驻留内存才有低延迟。这条"图必须装进 RAM"的约束,是 pgvector 在上亿向量上的天花板——1 亿条 1536 维 fp32 向量光原值就 ~600GB。pgvectorscale 要拆的就是这个约束。
先把 pgvector 的甜点区说诚实。它不是被周边项目"打败"了,而是把自己的领域做到了收敛:类型、运算符、HNSW、iterative scan 这套,对"数据已经在 Postgres 里、向量规模在千万级以内、要和租户/语言/时间一起过滤、要事务一致性"的场景——也就是前四章那条多租户 SQL 的全部场景——已经够用且稳定。停在 0.8.2 不是停滞,是这一层的问题基本解完了。新东西,发生在它之外。
StreamingDiskANN:把"图必须装进内存"改成"压缩副本装进内存"
底层机制(比文档深一层):pgvectorscale(Tiger Data,2025)给 Postgres 加了一个全新的索引访问方法 diskann,底子是微软的 DiskANN 图算法,但做成了 streaming。关键设计是把一条向量拆成两份存:
- 内存里只放压缩副本:每条向量经 SBQ(下面讲)压成几十到几百字节,整张图的压缩版能驻留内存。搜索阶段在压缩副本上跑图遍历——内存够、图不必装全精度。
- SSD 上放全精度原值:图遍历定位到候选后,再从磁盘流式读出这些候选的全精度向量做 rescore(重新精确算距离、重排)。
于是成本结构变了:内存成本被压缩副本的大小绑定,精度成本被磁盘 rescore 绑定。这正好绕开第 2 章那条"全精度图必须装进 RAM"的悬崖——图遍历这条热路径不再被原值大小拖住,原值只在最后 rescore 那一步从 SSD 顺序读。"streaming"指的是它能持续从图里吐候选、配合 rescore 动态决定要不要继续往下挖,而不是一次性取一个固定的候选池。
SBQ 与 Filtered-DiskANN
SBQ(Statistical Binary Quantization)是 pgvectorscale 用来生成那份"内存压缩副本"的量化方法——统计学加权的二值量化,比朴素的逐位取符号保留更多信息,配合磁盘上的全精度 rescore,把"压缩省内存"和"rescore 保精度"两件事接到了一起。它和第 1 章见过的 binary_quantize()、以及 §5.3 要讲的 RaBitQ 是同一个家族的不同手法。
pgvectorscale 还把第 4 章的过滤难题往前推了一步:它支持 label-based filtered search(Filtered-DiskANN)——把标签信息编进图结构,让过滤在图遍历内部就生效,而不是像 pgvector 那样靠 post-filter / iterative scan 在索引之外补救。这正面回应了第 4 章"带 WHERE 过滤在大规模下尾延迟爆炸"的痛点。
Tiger Data 2025 年 5 月公布的基准:5000 万向量、99% 召回下约 471 QPS;对比托管的 Pinecone storage-optimized(s1)实例,宣称 p95 延迟低 28×、吞吐高 16×、成本低 75%。这些是厂商自测数,方向(DiskANN 在大规模 + 高召回区间吃香)可信,绝对值照例要在你自己的数据分布上复测——和第 2 章"召回必须自己量、不能凭感觉"是同一条纪律。
pgvectorscale 把全精度向量放在 SSD、只在内存放压缩副本。那么在一台内存远小于向量原值总量的机器上(比如 600GB 向量、64GB 内存),它相比 pgvector 原生 HNSW 的关键优势是什么?代价又落在哪里?
展开答案(先停 10 秒)
优势:pgvector 的 HNSW 在这台机器上根本建不起来——全精度图装不进内存,建索引和查询都会退化成磁盘随机访问(第 2 章构建悬崖)。DiskANN 只要求压缩副本装进内存(600GB 经 SBQ 可能压到几十 GB),图遍历因此仍跑在内存里,规模上限被解锁。
代价:每次查询多了一步磁盘 rescore——要从 SSD 读出候选的全精度原值重排。这把延迟的下限从"纯内存"抬到了"含一次 SSD 顺序读",所以它换来的是规模,牺牲的是单查询最低延迟。在向量能全部装进内存的中小规模上,pgvector 原生 HNSW 反而更快——这条正是 §5.4 决策树的一个分叉。
5.2其它路线:VectorChord,与非-HNSW 的 AlloyDB ScaNN
同一时期 Postgres 向量生态冒出两个强力挑战者——VectorChord 把建索引砍快两个数量级,AlloyDB 干脆没选 HNSW。
选型不是"pgvector vs 一个专用库"的二选一。Postgres 内部就有多条路线在竞争,各自押注不同的瓶颈:VectorChord 押"建索引太慢",AlloyDB ScaNN 押"HNSW 的内存/构建成本太高"。看懂它们押的是什么,才知道你的瓶颈该往哪条路靠。
VectorChord:RaBitQ 量化的 DiskANN
VectorChord(pgvecto.rs 的继任者,TensorChord)走的也是 DiskANN + 量化路线,但量化用的是 RaBitQ——一种带理论误差界的随机化二值量化。它的 v1.0(2025)主打两个卖点:建索引比 pgvector HNSW 快约 100×、查询 QPS 约 2×,并打出"400k 向量 1 美元"的成本口号。把它放进选型版图:当你的痛点是建索引/重建索引太慢(回想第 2 章百万级建图动辄几十分钟、第 3 章 churn 后要 REINDEX),VectorChord 是 Postgres 生态内一个真实的备选,而不必直接跳到专用库。
AlloyDB ScaNN:连 Google 都没选 HNSW
这是给 2024 年那个"向量索引 = HNSW"直觉的最大一记纠正。Google 的 AlloyDB(兼容 Postgres)在 2025 年中 GA 的向量索引,用的不是 HNSW,而是 ScaNN——Google 自研、驱动其内部十亿级检索的算法。机制上 ScaNN 是另一条路:分区(partition)→ 量化(quantize)→ rescore,更像 IVF 家族的精装版,而非图索引。它宣称查询快至 4×、建索引快 8×、内存省 3–4×,能扩到约 10 亿向量、p95 < 25ms。
第 2 章把 HNSW 讲成 pgvector 的默认与主力,没错——但"默认"不等于"唯一最优"。当一个有十亿级检索实战、自己造过无数索引的团队(Google)在 Postgres 兼容产品里主动绕开 HNSW、押注 partition+quantize+rescore 时,它在告诉你:图索引在超大规模 + 强量化区间未必占优,IVF/ScaNN 那条"先粗分桶、再量化、再精排"的老路线,配上现代量化反而更省内存、更好扩。把这当成选型时的一个反直觉锚点:不要因为教程从 HNSW 讲起,就以为终点也一定是 HNSW。
顺带一提:Postgres 终于有了原生 BM25
第 4 章讲混合检索(hybrid + RRF)时,词法这条腿当时只能用 Postgres 内置的 ts_rank 全文检索——它能跑,但打分不是真正的 BM25,相关性弱于专业搜索引擎。这一块现在被补上了:ParadeDB pg_search(V2,2025 年底)和 Tiger pg_textsearch 把真正的 BM25 带进了 Postgres,提供 @@@ 操作符和 USING bm25 索引。落到第 4 章的混合检索:向量腿走 pgvector 的 <=>,词法腿从 ts_rank 升级成 BM25,两路结果再用 RRF 融合——整条混合检索链可以全部留在 Postgres 内完成,不必为了一个像样的 BM25 引入外部搜索引擎。详见 第 4 章的混合检索一节。
5.3量化阶梯:用精度换体积,rescore 兜回精度
量化是一架阶梯——fp32 → fp16 → 二值,索引每级缩小约 2×,而 rescore 这一步把召回损失基本兜回来。
前面三条新路线(StreamingDiskANN 的 SBQ、VectorChord 的 RaBitQ、ScaNN 的 quantize)有一个共同的底层动作:量化。它也是 pgvector 自己就能用的能力(第 1 章的 halfvec / bit)。看懂这架阶梯和它为什么"几乎免费",是理解整个前沿的钥匙——所有这些项目省内存的本钱,都在这里。
底层机制(比文档深一层):量化就是用更少的比特表示每个分量,索引体积随之线性缩小。pgvector 原生就覆盖了这架阶梯的三级:
vector(fp32,4 字节/维):基线。1536 维 = 6KB/条。halfvec(fp16,2 字节/维):体积砍半。半精度浮点对 embedding 这种本就含噪的数据几乎无损,召回损失通常 <1%。这是性价比最高的一级,很多生产系统的默认选择。- 二值
bit(1 比特/维,0.125 字节/维):经binary_quantize()把每个分量压成 1 位(取符号),体积只剩 fp32 的 1/32,距离用 Hamming(按位异或计数)算,极快。SBQ、RaBitQ 是这一级更聪明的变体。
为什么压成 1/32 召回还能撑住?答案是 rescore(两阶段检索)。它的套路对前面每条路线都成立:
- 粗筛:在便宜的量化表示上检索,快速捞出一个比 k 大得多的候选 shortlist(比如要 top-10,先用二值距离捞 top-200)。
- 精排:只对这 200 个候选,用全精度原值重新精确算距离、重排,取真正的 top-10。
关键在于:量化只用在"粗筛排序"这步,它只需要把对的候选圈进 shortlist 即可,不需要把它们之间的精细排名也算准——精细排名由全精度 rescore 负责。于是索引缩 2×–32×,召回损失往往只有 1–2%。这就是第 5.1 节 DiskANN"内存放压缩副本、磁盘放全精度 rescore"在 pgvector 层面的同构版本。
-- ① halfvec:性价比最高的一级,索引砍半,召回几乎不掉
CREATE INDEX ON doc_chunks
USING hnsw ((embedding::halfvec(1536)) halfvec_cosine_ops);
-- ② 二值 + rescore:先用 Hamming 在 bit 上粗筛 top-200,再用全精度精排 top-10
SELECT id, content
FROM (
SELECT id, content, embedding
FROM doc_chunks
ORDER BY binary_quantize(embedding)::bit(1536) <~> binary_quantize($1) -- Hamming 粗筛
LIMIT 200
) AS shortlist
ORDER BY embedding <=> $1 -- 全精度 rescore 精排
LIMIT 10;
阶梯越往下,越依赖 rescore 把精度兜回来,也越吃 shortlist 大小:二值粗筛若 shortlist 取太小(比如直接 top-10 不 rescore),召回会明显塌。规律是——halfvec 几乎可以无脑用、单独用;二值/SBQ/RaBitQ 必须配 rescore 且要调 shortlist 倍率。别把"压 32× 召回只掉 1%"理解成"二值距离本身准",那 1% 是 rescore 换来的。
5.4选型决策:何时 pgvector 赢,何时该换
把前四章的内核行为和这一章的周边路线合到一张决策树上——分界线落在数据量、过滤尾延迟、热路径性质和 churn 这四个轴上。
选型最容易犯的错是"听说专用库快就上专用库"或"反正有 Postgres 就硬扛"。两者都漏了关键变量。这棵树把"换不换"拆成四个可判定的问题,每个问题都直接对应前面某一章讲过的机制——你不是在背结论,是在沿着前四章的因果链做判断。
pgvector 赢的场景
- 数据已经在 Postgres 里:向量和业务表同库,省掉一套独立向量库的双写、同步、运维。这是 pgvector 最大的结构性优势,专用库给不了。
- 规模 ≲10M 向量:全精度图能舒服地装进内存,HNSW 低延迟,没到要 DiskANN 的地步。
- 要事务一致性:向量写入和业务写入在同一个事务里原子提交——"文档入库即可被检索、回滚即一起消失"。专用库的最终一致在这里是硬伤。
- 要和关系字段一起过滤:第 1 章那条
WHERE tenant_id=42 AND lang='zh' ORDER BY embedding <=> $1——租户、语言、时间窗的过滤和向量检索焊在一条 SQL 里,走第 4 章的 partial index / iterative scan。这是 pgvector 的主场。 - 中等 churn:写入/更新频率在 vacuum 追得上的范围内(第 3 章)。
pgvector 吃力、该上 pgvectorscale 或专用库的场景
- 上亿向量:全精度图装不进内存,撞第 2 章构建悬崖 → 上 pgvectorscale(StreamingDiskANN)或专用库。
- 纯向量热路径、延迟由向量主导:没有重的关系过滤、QPS 极高、延迟预算苛刻,向量检索本身就是瓶颈 → 专用库(Qdrant / Milvus)为这条路径做了极致优化。
- 大规模 + 重过滤的尾延迟:上亿向量还要带高选择性过滤,第 4 章的 post-filter / iterative scan 尾延迟会爆 → pgvectorscale 的 Filtered-DiskANN,或专用库的原生 payload 过滤。
- 极高 churn:写入快到 vacuum 追不上、召回持续腐烂、REINDEX 频率高到影响可用性(第 3 章)→ 专用库的写入路径通常对高频更新更友好。
| 维度 | pgvector | pgvectorscale | AlloyDB ScaNN | 专用库(如 Qdrant) |
|---|---|---|---|---|
| 规模上限 | 舒适 ≲10M,千万级可行 | 5000 万–亿级(DiskANN 上盘) | ~10 亿(partition+quantize) | 十亿级,水平分片 |
| 过滤 | post-filter / iterative / partial(第 4 章) | Filtered-DiskANN,图内过滤 | 内联过滤 + rescore | 原生 payload 过滤,强项 |
| 运维成本 | 最低——就是你的 Postgres | 低——装个扩展,仍是 Postgres | 托管,绑定 GCP | 多一套独立系统要运维 |
| 一致性 · 事务 | 完整 ACID,与业务同事务 | 完整 ACID(继承 PG) | 完整 ACID(继承 PG) | 多为最终一致,需双写同步 |
| 何时选 | 数据在 PG + ≲10M + 要过滤/事务 | 同上但规模/尾延迟越界,想留在 PG | 已在 GCP、要托管、十亿级 | 纯向量热路径、极高 churn、超大规模 |
注意决策树没有一个判断是新知识:「规模超界」是第 2 章构建悬崖的工程化,「带过滤的尾延迟」是第 4 章 post-filter 的规模化,「churn 追不上」是第 3 章召回腐烂的极端化。选型之所以能做对,正因为你已经从机制上理解了 pgvector 在每个轴上为什么会到边界——而不是背一张"什么时候用什么"的对照表。这也是这份教程把"选型"放在最后、而非开头的原因。
§本章 self-check
先合上教程,把答案写在纸上或编辑器里,再点开对照。直接展开等于把这一节当再读一遍。
- pgvectorscale 的 StreamingDiskANN 把哪一条 pgvector 硬约束拆掉了?它用什么两层结构做到的?
- 二值量化把索引压成 fp32 的 1/32,召回却只掉 1–2%。是哪一步把召回兜回来的?为什么量化"不准"也没关系?
- AlloyDB 用的不是 HNSW 而是 ScaNN。ScaNN 的机制路线是哪三步?这件事推翻了一个什么常见直觉?
- 一条查询:数据在 Postgres、向量 800 万、带
tenant_id过滤、写入中等。按决策树该选谁?说出走到终点的判断链。
答案(先做完再展开)
- 拆掉的是第 2 章的"全精度 HNSW 图必须装进内存"约束。两层结构:内存放 SBQ 压缩副本供图遍历、SSD 放全精度原值供 rescore。于是内存成本被压缩副本绑定、精度成本被磁盘 rescore 绑定,规模上限解锁。
- 是 rescore(两阶段检索)兜回来的:二值距离只用于粗筛,把对的候选圈进一个比 k 大得多的 shortlist;最终 top-k 由 shortlist 上的全精度重排决定。量化只需"圈对候选",不需要算准它们之间的精细排名——精细排名是全精度 rescore 的活,所以量化"不准"不致命。
- ScaNN 路线是 分区(partition)→ 量化(quantize)→ rescore,更接近 IVF 家族而非图索引。推翻的直觉是"向量索引就该用 HNSW / 图索引最优"——连 Google 在超大规模 + 强量化场景都主动绕开了 HNSW。
- 选 pgvector。判断链:在 Postgres(是→往下)→ 规模 >1 亿?(800 万,否→往下)→ 纯向量热路径?(有
tenant_id关系过滤,否→往下)→ churn 极高?(中等,否→终点)= pgvector 主场,照第 1–4 章做(partial index / iterative scan + halfvec)。
你的库已经在 Postgres、向量涨到 8000 万、且带高选择性的 tenant_id 过滤,尾延迟开始爆。在"换专用库"之前,留在 Postgres 内还有哪两步可打,各自动了哪一章的哪根杠杆?
规模逼近第 2 章构建悬崖、过滤尾延迟是第 4 章的老问题——但题目限定"先别跳专用库"。请给出留在 Postgres 生态内的两级递进方案,并说清每一步分别在"内存约束"和"过滤位置"这两个轴上做了什么。
提示(卡住再展开)
第一步动量化轴(§5.3):先把列降到 halfvec 或对 HNSW 配二值粗筛 + rescore,索引体积砍 2×–32×,让全精度图/压缩副本重新装得进内存——这是用精度换体积缓解第 2 章的内存约束,列和查询都还在原生 pgvector 内。
第二步换索引引擎(§5.1–5.2):装 pgvectorscale,用 StreamingDiskANN 把全精度原值挪到 SSD(彻底拆掉"图装进内存"约束),并用它的 Filtered-DiskANN 把 tenant_id 过滤推进图遍历内部——这同时动了"内存约束"轴(原值上盘)和"过滤位置"轴(从第 4 章的索引外 post-filter 变成图内过滤),而且仍然是一个 Postgres 扩展、不离开生态。只有这两步都不够时,才轮到专用库。