向量数据库

pgvector:关系库内的向量检索

核心系统架构约 25 分钟kp-020

前置知识

一句话定义

pgvector 是 PostgreSQL 的开源扩展:给表加 vector 列、建 HNSW 或 IVFFlat 索引、用 SQL 完成"相似度排序 + 任意 WHERE 过滤 + JOIN 事务"——把向量检索装进最成熟的关系数据库生态。

为什么重要

pgvector 是"关系库扩展"谱系的旗手,也是选型讨论的起点:如果数据已在 PostgreSQL、量级在千万级以内、过滤逻辑复杂,它的综合成本几乎必然最低。它的天花板(索引维度上限、单机写扩展、大表索引构建时长)同样清晰——知道边界与知道优势同样重要。

前置知识

kp-007(IVF 参数——lists/probes 的原型)、kp-008(HNSW 参数——m/ef 的原型)、kp-018(谱系定位)。

核心概念

原理与机制

最小可用路径(可执行步骤):

CREATE EXTENSION vector;
CREATE TABLE docs (id bigserial PRIMARY KEY, body text,
                   embedding vector(1024), tenant_id int, created_at timestamptz);
-- 建索引(二选一):
CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops) WITH (m=16, ef_construction=64);
CREATE INDEX ON docs USING ivfflat (embedding vector_cosine_ops) WITH (lists=1000);
-- 查询(先在会话里调在线参数):
SET hnsw.ef_search = 100;                -- 或 SET ivfflat.probes = 20;
SELECT id, body FROM docs
WHERE tenant_id = 42 AND created_at > now() - interval '30 days'
ORDER BY embedding <=> $1 LIMIT 10;       -- <=> 余弦距离, <-> L2, <#> 内积

关键机制与约束:

  1. 索引维度上限:普通 vector 列的 HNSW/IVFFlat 索引只支持约 2000 维(halfvec 提高上限),超高维模型需先降维或用 halfvec。
  2. 索引不在建表时自动生效:先灌数再建索引(IVFFlat 还要求建索引时表里有数据供聚类)。
  3. 过滤走组合执行:WHERE 条件与向量排序联合优化;当规划器估计过滤后行数很少时可能选择位图扫描甚至顺序扫描,用 EXPLAIN ANALYZE 确认是否走了索引。
  4. 更新的代价:HNSW 索引随高频 UPDATE/DELETE 退化,需要 REINDEX 周期;大表 REINDEX 以小时计。
  5. 扩展手段:halfvec 降内存、分区表按租户/时间分区、只读副本分担查询。

公式或模型

本节不适用:产品实操篇,参数语义继承自 kp-007/008 的公式体系。

图示

SQL 查询 ─► 规划器 ─┬─ 走向量索引(HNSW/IVFFlat) + 位图过滤  ✔ 快
                    └─ 估计过滤后行数过少 → 顺序扫描全表    ✘ 秒级灾难
 EXPLAIN ANALYZE 是确认走哪条路的唯一方式

实例或案例

SaaS 文档助手:业务数据本在 PostgreSQL(用户、权限、文档元数据),新增 embedding 列 + HNSW 索引即可支持语义搜索,权限过滤直接复用既有 WHERE org_id=… AND visibility=…,与业务表 JOIN 拼装答案上下文,备份/审计/高可用全部沿用 RDS 现状——零新增系统。当文档量增长到 2 亿、p99 逼近 200 毫秒时,迁移信号出现:考虑 halfvec 量化、分区,或迁往专用向量库(kp-027 决策树 Q1 分支)。

直观类比

pgvector 是给家用轿车(PostgreSQL)加装行李架(向量索引):日常购物完全够用、不需要再买货车;但要每周搬十吨货(亿级、高并发向量负载),就该换卡车而不是无限加固轿车。

常见误区

  1. "pgvector 性能天然不如专用库"——同参数同硬件下 HNSW 检索速度差距不大;真正差距在超大库建索引时长、高频写退化、分布式能力,不是单点查询。
  2. "加了 WHERE 就自动高效过滤"——规划器可能放弃向量索引;过滤场景必须 EXPLAIN 验证,必要时用 CTE + ORDER BY embedding 的写法或分区引导执行计划。
  3. "probes/lists 可以随便改"——lists 建库后改动需重建索引;probes 是会话级在线参数,但必须在同会话/连接池内生效(连接池复用会"丢"SET,需在事务或连接初始化里设置)。

自测题

  1. 一条语义查询莫名变成秒级,第一步做什么?
  2. 答:EXPLAIN ANALYZE 看执行计划——大概率规划器放弃向量索引走了顺序扫描;对策:检查过滤选择率、调整统计信息、改写查询或分区。

  3. 使用 3072 维嵌入模型直接建 pgvector 索引会遇到什么?
  4. 答:超过索引维度上限(普通 vector 约 2000 维);先截断/Matryoshka 降维,或改用 halfvec 类型,或换支持高维的引擎。

  5. 连接池环境下 SET hnsw.ef_search 为什么会"失效"?
  6. 答:SET 是会话级的,连接归还池后可能被其他请求复用;应在事务内设置,或把参数写进连接初始化语句,确保每次取用的连接都带参数。

与其他知识点的关系

kp-007/008 是其两类索引的原理原型;kp-021 的单机专用库是它的对照方案;kp-027 决策树中"数据已在 PG"分支直达本篇。

延伸阅读

pgvector 官方项目文档(开源项目,参数与类型随版本演进)——以最新文档核对索引参数与维度上限;本库仅陈述原理与经验区间。

相关知识点