Erdmates Logo
Erdmates
返回博客
pgvectorRAGPostgreSQLAI

用pgvector设计RAG向量表:从维度、索引到过滤

以pgvector 0.8为准,整理在PostgreSQL中用pgvector存储文档嵌入向量时的表结构、各向量类型的维度限制、HNSW索引以及元数据过滤的设计。

2026年10月12日9 分钟阅读

为什么要把向量存储在PostgreSQL中

RAG(检索增强生成)是一种找出与问题含义相近的文档片段,并将其一并交给LLM的方式。为了计算"含义相近",需要把文档片段转换为数值向量(嵌入向量,embedding)进行存储。

pgvector是一个开源扩展,可以在PostgreSQL中存储向量并按相似度进行检索(2026年10月1日发布0.8.7)。不使用单独的向量数据库而放在PostgreSQL中,好处是可以与文档的权限、租户、修改时间等现有数据在同一事务中、通过同一JOIN进行处理。正因如此,表设计会左右检索质量和性能。

1. 拆分文档与分块的结构

嵌入向量通常不是针对整个文档,而是以按一定长度切分的**分块(chunk)**为单位生成。将文档与分块拆分为1:N关系。

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE documents (
  id          BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  tenant_id   BIGINT      NOT NULL,
  title       TEXT        NOT NULL,
  source_url  TEXT,
  updated_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE document_chunks (
  id           BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  document_id  BIGINT NOT NULL REFERENCES documents (id) ON DELETE CASCADE,
  tenant_id    BIGINT NOT NULL,
  chunk_index  INT    NOT NULL,
  content      TEXT   NOT NULL,
  embedding    vector(1536) NOT NULL,
  model        TEXT   NOT NULL,
  embedded_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (document_id, chunk_index)
);

设计要点如下。

  • vector(1536)的维度必须与嵌入模型的输出维度相同。不同维度的向量不能放入同一列
  • model列:不同模型生成的向量无法相互比较。更换模型时,可以通过该列找到需要重新生成的行
  • 分块中也保留tenant_id:检索时几乎总是按租户过滤,因此无需JOIN即可直接过滤,也可以用于下文的部分索引和分区
  • ON DELETE CASCADE:删除文档时,其分块和向量也会一并删除,已删除的文档不会残留在检索结果中
  • 比较embedded_at与文档的updated_at,可以找出原文变更后尚未重新嵌入的分块

2. 向量类型与维度限制

pgvector提供四种类型,可存储的维度与可创建索引的维度不同。vector和halfvec最多可存储16,000维,但索引上限低于此值。

类型可创建索引的上限
vector2,000维
halfvec(半精度)4,000维
bit(二进制)64,000维
sparsevec(稀疏)1,000个非零元素(存储最多16,000个)

嵌入向量超过2,000维时,无法直接在vector列上创建索引。此时应使用转换为半精度的表达式索引。查询也必须按与索引相同的表达式排序,才能用上索引。

-- 将3072维嵌入向量以半精度建立索引
CREATE INDEX ON document_chunks_large
  USING hnsw ((embedding::halfvec(3072)) halfvec_cosine_ops);

SELECT id, content
FROM document_chunks_large
ORDER BY embedding::halfvec(3072) <=> $1::halfvec(3072)
LIMIT 5;

3. 距离运算符与HNSW索引

pgvector的距离运算符包括<->(L2)、<#>(负内积)、<=>(余弦距离)、<+>(L1),以及用于二进制向量的<~>(汉明)、<%>(杰卡德)。应选择嵌入模型推荐的距离,并且索引的运算符类(opclass)必须与查询的运算符一致。索引在ORDER BY为距离运算符的升序时使用。

索引有两种。

  • HNSW:多层图。检索性能好,但构建较慢,占用内存更多。不需要训练步骤
  • IVFFlat:将向量划分为多个列表。构建较快,占用内存更少,但检索性能低于HNSW
-- 余弦距离HNSW索引(默认值:m = 16, ef_construction = 64)
CREATE INDEX ON document_chunks USING hnsw (embedding vector_cosine_ops);

-- 检索时的候选数量(默认40)。调高则召回率↑ 速度↓
SET hnsw.ef_search = 100;

SELECT id, document_id, content
FROM document_chunks
WHERE tenant_id = 42
ORDER BY embedding <=> $1
LIMIT 5;

当图能够放入maintenance_work_mem时,HNSW索引的构建速度会快得多。在大表上创建索引时,请一并检查该值。

4. 过滤:结果不足的问题及解决方案

在近似索引中,先扫描索引,之后才应用过滤条件。以pgvector文档中的例子来说,如果符合条件的行占全部的10%,且hnsw.ef_search为默认值40,那么平均只剩下4行。也就是说,即使指定LIMIT 5,也可能得不到5条结果。

应根据情况选择解决方案。

迭代索引扫描(从0.8.0开始)。 持续扫描索引,直到收集到足够的结果。

SET hnsw.iterative_scan = strict_order;   -- 严格保持距离顺序
-- 或者
SET hnsw.iterative_scan = relaxed_order;  -- 顺序可能略有偏差,但召回率更好

为过滤列创建普通索引。 如果条件只选出全部行中的一小部分,先用B-tree索引过滤会更好。

CREATE INDEX ON document_chunks (tenant_id);

常用的值只有几个时用部分索引,值很多时用分区。

-- 特定租户专用的向量索引
CREATE INDEX ON document_chunks USING hnsw (embedding vector_cosine_ops)
  WHERE (tenant_id = 42);

如果值的种类很多,pgvector文档建议像PARTITION BY LIST (tenant_id)这样按过滤列进行分区。

5. 运维检查清单

  • 更换嵌入模型时:通过model列筛选目标,在其他列或表中生成新向量后再切换,检索就不会中断
  • 原文变更时:删除该文档的分块后重新生成,或定期找出embedded_at < updated_at的分块进行更新
  • 确认维度限制:需要索引的列必须在对应类型的索引维度上限之内
  • 衡量检索质量:ef_search和迭代扫描的设置是在准确度与速度之间进行取舍。请用实际查询测量召回率后再决定

使用Erdmates设计

RAG模式的核心是文档–分块的1:N关系、级联删除的外键,以及用于过滤的租户键。在Erdmates中先把这些关系画成ERD,团队就可以对着同一张图,决定把向量列放在哪张表、用哪个列来过滤。

总结

在pgvector设计中,决定性能与质量的归根结底是平常的数据库设计:拆分文档与分块,记录模型与更新时间,选择符合维度上限的类型,制定与过滤条件相匹配的索引策略(迭代扫描、部分索引、分区)。具备这四点,向量检索也能以与现有数据同等的水平进行管理。

立即使用Erdmates开始

使用AI驱动的ERD编辑器开始数据库设计。免费使用。

免费试用演示免费开始

相关文章

bigint、UUID v4 还是 UUID v7?主键选择指南(含 PostgreSQL 18 的 uuidv7())

比较 bigint、UUID v4 和 UUID v7 主键的优缺点,介绍 PostgreSQL 18 内置的 uuidv7() 带来的变化,以及不同场景下的选择方法。

被AI代理读取的数据库:MCP时代的模式设计原则

AI代理通过MCP直接连接数据库的情况越来越多。本文整理如何设计名称、注释和约束,让代理不会误解模式,以及如何安全地划分权限。

PostgreSQL 19预览:影响模式设计与运维的变化(基于Beta 4)

以官方发布说明(Beta 4)为准,整理即将正式发布的PostgreSQL 19的变更中直接影响表设计、迁移和运维的内容。同时介绍在Beta阶段被撤回的功能,以及升级前需要确认的行为变化。

Erdmates Logo
Erdmates

使用自然语言设计数据库,通过AI驱动的ERD编辑器与团队实时协作。

服务

  • 功能介绍
  • 价格方案
  • 演示
  • SQL 转 ERD

资源

  • 博客
  • 帮助
  • 联系我们

法律声明

  • 服务条款
  • 隐私政策
  • 第三方提供
公司名称: Produx|代表人: 최정회
地址: 강원특별자치도 원주시 솔우물2길 4-1 (무실동)
电子邮件: master@erdmates.com
隐私保护负责人: 최정회|托管服务提供商: Amazon Web Services

© 2026 Produx. 版权所有。