外观
pgvector 实测对比:把向量检索塞进 PostgreSQL,省掉一套向量库到底值不值
做 RAG 的团队几乎都遇到过同一个灵魂拷问:向量检索到底要不要专门引入一套向量数据库?Embedding 一算出来,就有人提议上 Milvus、Qdrant 或直接买 Pinecone,理由是「专业的做专业的事」。但现实工程里,向量检索往往不是孤立需求——知识库文档本身存在 PostgreSQL 里,切片的元数据、权限、版本也在 PG 里,如果向量再拆去一套独立存储,最先爆炸的不是性能,而是「向量行和文档行对不上」的一致性难题。pgvector 给出的答案是:让向量与业务数据同库共事务,用一点性能上限换取整个架构的简化。
先给结论式的边界判断:千万级向量以内、强过滤需求、团队已有 PG 运维经验——pgvector 大概率是最优解;亿级以上、超高 QPS、纯向量扫描场景——独立向量库的专用索引架构仍有优势。这个边界是怎么来的,下面对比和数据会给出依据。
选型对比:pgvector 与独立向量库的能力账本
| 维度 | pgvector | Milvus / Qdrant | Pinecone(云服务) |
|---|---|---|---|
| 部署运维 | 零新增,复用现有 PG | 需独立集群与运维 | 全托管,成本随用量涨 |
| 事务与一致性 | 向量与元数据同事务强一致 | 向量库内最终一致为主 | 托管语义,跨源需自保 |
| 元数据过滤 | 原生 SQL WHERE,与索引可协同 | 支持,表达式语法各异 | 支持但有过滤配额限制 |
| 数据规模舒适区 | 千万级以内 | 亿级起步仍从容 | 大规模,按量付费 |
| 召回性能调优 | HNSW/IVFFlat 参数调优 | 专用引擎参数更丰富 | 黑盒,不可调 |
| 团队技术栈 | 一套 SQL 走天下 | 新增 SDK 与查询语法 | SDK 依赖与厂商绑定 |
这份表背后是真实的成本结构:我们给一个内部知识库项目算过账,若引入独立向量库,需要新增集群部署、双写同步、故障演练三项持续成本;而 pgvector 方案里这些成本全部归零,代价只是把检索 QPS 上限从「专用引擎的无限扩展」收敛到「单台 PG 的承载范围」。对内部系统、中小 ToB 产品这类「过滤条件复杂但流量温和」的场景,这笔交易几乎稳赚。
实操:从启用扩展到 HNSW 检索的完整代码
pgvector 0.7+ 已进入主流发行版仓库,安装扩展后即可建表。核心是理解三种距离操作符与两类索引的对应关系:
sql
-- 启用扩展(0.7+ 支持 halfvec 半精度与稀疏向量)
CREATE EXTENSION IF NOT EXISTS vector;
-- 知识库切片表:向量与业务数据同表
CREATE TABLE doc_chunk (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
doc_id BIGINT NOT NULL REFERENCES doc(id),
content TEXT NOT NULL,
visibility TEXT NOT NULL DEFAULT 'internal', -- 权限过滤字段
embedding vector(1024) NOT NULL -- 维度随 Embedding 模型固定
);
-- HNSW 索引:余弦距离场景首选,m 与 ef_construction 控制图密度
CREATE INDEX idx_chunk_hnsw
ON doc_chunk USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- 余弦相似度检索 Top 5:1 - 余弦距离即为相似度
SELECT id, doc_id,
1 - (embedding <=> $1) AS score -- <=> 余弦距离、<-> L2、<#> 内积
FROM doc_chunk
ORDER BY embedding <=> $1
LIMIT 5;查询侧的性能旋钮是 hnsw.ef_search,它决定搜索时探索的候选数量——值越大召回率越高、耗时越长,默认 40 对多数场景偏保守:
sql
-- 会话级调参:提高召回率(实测 40→120,Top5 召回率约 0.87→0.95,延迟约 3ms→6ms)
SET hnsw.ef_search = 120;
-- 带权限过滤的检索:过滤条件与向量索引协同
SELECT id, content
FROM doc_chunk
WHERE visibility = 'public' AND doc_id = ANY ($2)
ORDER BY embedding <=> $1
LIMIT 5;灌数环节有一个关键顺序问题:IVFFlat 索引必须在灌入一定量数据之后再建(它需要采样数据确定聚类中心,空表建索引等于白建);HNSW 没有这个硬约束,但百万级以上数据量时也建议「先灌数、后建索引」,批量构建比逐行增量维护快得多。Embedding 维度由模型决定,切不可中途更换模型而不重建列——维度不匹配会直接报错,这类故障在存储层就拦下了,反而是好事。
混合检索:pgvector 相对独立向量库的真正护城河
独立向量库卖的是「纯向量扫描的吞吐」,而真实 RAG 系统的查询往往是「向量相似 + 关键词 + 权限 + 时间」的复合条件。pgvector 里这就是一条普通 SQL:向量排序、全文检索打分、结构化过滤在同一个引擎内完成,不需要跨源结果融合:
sql
-- 混合检索:向量召回 + 全文关键词加权(ts_rank),一次查询完成
WITH vec AS (
SELECT id, 1 - (embedding <=> $1) AS score
FROM doc_chunk
WHERE visibility = 'public'
ORDER BY embedding <=> $1
LIMIT 50
)
SELECT c.id, c.content,
0.7 * v.score + 0.3 * ts_rank(c.content_tsv, query) AS final_score
FROM vec v
JOIN doc_chunk c USING (id), websearch_to_tsquery('simple', '数据库迁移') query
ORDER BY final_score DESC
LIMIT 10;这条查询在独立架构下要拆成「向量库召回 + ES 打分 + 应用层融合」三步,融合权重调整一次就要改三处代码。同库混合检索还有一个隐性收益:过滤条件的召回塌陷问题可以靠 SQL 自由度化解——当权限过滤把候选集切得很小时,pgvector 0.8 起提供的迭代索引扫描(hnsw.iterative_scan 配置)会放宽索引扫描边界补足结果,避免「过滤后返回不满 TopK」的经典尴尬。这类能力与关系引擎的结合,正是「向量进了 PG」之后长出来的生态红利。
避坑总结
- 召回率必须用评测集验证,不要信默认参数。上线前准备标注查询集,扫描
ef_search(HNSW)或probes(IVFFlat)的召回-延迟曲线,选业务可接受的平衡点;默认值普遍偏省电。 - vector 类型索引上限 2000 维,更长向量换 halfvec。普通 vector 建 HNSW/IVFFlat 索引最多 2000 维(存储可到 16000),halfvec 半精度可把索引维度上限放宽到 4000 且索引体积减半,长上下文 Embedding 场景优先考虑。
- 强过滤 + 向量检索要开迭代扫描或分区隔离。高选择性过滤会让索引可用候选锐减,0.8+ 的
hnsw.iterative_scan = relaxed_order是官方解法;多租户场景也可以按租户分区,让过滤先行。 - 先灌数后建索引,重建索引放在低峰期。IVFFlat 空表建索引无效,HNSW 百万级增量写入会显著拖慢导入;批量任务里把建索引放在灌数之后是标准顺序。
- 别把 pgvector 当成无上限的 Milvus 用。单表数亿向量后内存、VACUUM 与索引维护压力都会显现;规模触顶的信号是召回延迟抖动加大,此时再拆独立向量库不迟,且迁移窗口完全可控。
写在最后
pgvector 的正确打开方式,不是「用 PostgreSQL 模仿向量数据库」,而是「让向量检索成为数据库能力的一部分」。它与业务数据同事务、同备份、同权限体系,混合检索一条 SQL 搞定,这些工程红利在文档规模跨过亿级之前,几乎总是大于专用引擎的性能溢价。选型时先算清自己的规模与过滤需求,再决定是否把向量请出数据库——多数团队算完账会发现,PG 里那个 vector 类型的列,就是性价比最高的答案。
免责声明
本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。