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"。
  • 量化是一架阶梯:vector fp32 → halfvec fp16 → 二值 bit / SBQ / RaBitQ,索引体积从 4B/维 砍到 0.125B/维,而 rescore 兜底把召回损失压在 1–2% 内。
  • 连 Google 的 AlloyDB 都没选 HNSW,而是 ScaNN——这是给"HNSW 是唯一答案"这个 2024 年直觉的一记纠正。

前四章都站在一条 SQL 里面往下看零件。这一章把镜头拉远:同样这条多租户 RAG 查询,当向量数从 100 万涨到 1 亿、当 churn 高到 vacuum 追不上、当向量延迟变成热路径的瓶颈,该不该继续用 pgvector,又该换成什么。先把"什么稳定、什么在变、什么已过时"这条时间线讲清楚,再逐一拆 pgvector 周边的三条技术路线,最后给一棵能照着走的决策树。

现状速览 · 截至 2026-06 · 读法

稳定、可照学的内核: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 动态决定要不要继续往下挖,而不是一次性取一个固定的候选池。

内存(RAM) 压缩副本上跑图遍历 SBQ 压成几十字节 · 整图驻留 SSD(磁盘) 全精度原值 仅 rescore 时流式读出候选 候选 TID rescore 精确 top-k 内存定上限 · 磁盘定精度 不再受"图必须全装进 RAM"约束
图 5.1StreamingDiskANN 的两层结构:图遍历跑在内存里的压缩副本上,全精度原值留在 SSD,只在最后 rescore 时流式读出候选。注意:这张图直接对照第 2 章的构建悬崖——pgvector 的 HNSW 要求全精度图装进内存,DiskANN 把这条约束换成"压缩副本装进内存 + 原值流式读盘",内存成本与精度成本因此解耦。

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 过滤在大规模下尾延迟爆炸"的痛点。

数据点 · 2025-05 benchmark

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。

洞察 · 把 ScaNN 当成一面镜子

第 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(两阶段检索)。它的套路对前面每条路线都成立:

  1. 粗筛:在便宜的量化表示上检索,快速捞出一个比 k 大得多的候选 shortlist(比如要 top-10,先用二值距离捞 top-200)。
  2. 精排:只对这 200 个候选,用全精度原值重新精确算距离、重排,取真正的 top-10。

关键在于:量化只用在"粗筛排序"这步,它只需要把对的候选圈进 shortlist 即可,不需要把它们之间的精细排名也算准——精细排名由全精度 rescore 负责。于是索引缩 2×–32×,召回损失往往只有 1–2%。这就是第 5.1 节 DiskANN"内存放压缩副本、磁盘放全精度 rescore"在 pgvector 层面的同构版本。

索引体积 / 维 vector · fp32 4 B/维 · 基线 · 召回 100% ÷2 halfvec · fp16 2 B/维 · 损失 <1% ÷16 bit · 二值 / SBQ / RaBitQ 0.125 B/维 · 1/32 体积 rescore 兜底:量化粗筛 shortlist → 全精度精排 top-k 量化只需圈对候选,精细排名交给全精度 → 净召回损失常 <1–2% 越往下越省内存 越依赖 rescore 保精度
图 5.2量化阶梯:每往下一级,索引体积砍 2×–16×(fp32 的 4B/维 → 二值的 0.125B/维,共 32×),但rescore 用一遍全精度精排把召回兜回来。注意:量化的职责只是"把对的候选圈进 shortlist",精细排名永远由底部那条全精度 rescore 负责——这就是为什么压缩 32× 召回还能掉得很少。
quantize.sql SQL
-- ① 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 章)→ 专用库的写入路径通常对高频更新更友好。
数据已经在 Postgres? 否 从专用库起步 Qdrant / Pinecone / Milvus 是 规模 > 1 亿 向量? 是 pgvectorscale StreamingDiskANN · 留在 PG 否 纯向量热路径 延迟主导? 是 专用库 为纯向量延迟做极致优化 否 churn 极高 vacuum 追不上? 是 专用库 写入路径更扛高频更新 否 pgvector — 主场,照前四章做
图 5.3选型决策树。四个菱形判断各自对应前面一章的机制:「>1 亿」对应第 2 章构建悬崖、「纯向量热路径」对应第 1 章的过滤主场是否存在、「churn 极高」对应第 3 章召回腐烂。注意:只有四个问题全落在 pgvector 一侧(在 PG / ≲1 亿 / 有关系过滤 / churn 可控)才留在 pgvector;任一越界,先考虑 pgvectorscale 留在 Postgres 内,再考虑专用库。
表 5.1 · 四类方案横向对比(截至 2026-06)
维度pgvectorpgvectorscaleAlloyDB 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

先合上教程,把答案写在纸上或编辑器里,再点开对照。直接展开等于把这一节当再读一遍。

  1. pgvectorscale 的 StreamingDiskANN 把哪一条 pgvector 硬约束拆掉了?它用什么两层结构做到的?
  2. 二值量化把索引压成 fp32 的 1/32,召回却只掉 1–2%。是哪一步把召回兜回来的?为什么量化"不准"也没关系?
  3. AlloyDB 用的不是 HNSW 而是 ScaNN。ScaNN 的机制路线是哪三步?这件事推翻了一个什么常见直觉?
  4. 一条查询:数据在 Postgres、向量 800 万、带 tenant_id 过滤、写入中等。按决策树该选谁?说出走到终点的判断链。
答案(先做完再展开)
  1. 拆掉的是第 2 章的"全精度 HNSW 图必须装进内存"约束。两层结构:内存放 SBQ 压缩副本供图遍历、SSD 放全精度原值供 rescore。于是内存成本被压缩副本绑定、精度成本被磁盘 rescore 绑定,规模上限解锁。
  2. 是 rescore(两阶段检索)兜回来的:二值距离只用于粗筛,把对的候选圈进一个比 k 大得多的 shortlist;最终 top-k 由 shortlist 上的全精度重排决定。量化只需"圈对候选",不需要算准它们之间的精细排名——精细排名是全精度 rescore 的活,所以量化"不准"不致命。
  3. ScaNN 路线是 分区(partition)→ 量化(quantize)→ rescore,更接近 IVF 家族而非图索引。推翻的直觉是"向量索引就该用 HNSW / 图索引最优"——连 Google 在超大规模 + 强量化场景都主动绕开了 HNSW。
  4. 选 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 扩展、不离开生态。只有这两步都不够时,才轮到专用库。