在这里插入图片描述

不用折腾Milvus,不用花钱买Pinecone!你的老朋友PostgreSQL摇身一变就是顶级向量数据库,RAG开发的低成本王炸方案来了!在这篇文章里,大仙我要带你把pgvector的里里外外扒个干净。从“为什么要用它”到“怎么在生产环境不踩坑”,从索引选型到SQL实战,全文没有废话,只有血泪经验和可直接复制的正确姿势。读完这篇,你会发现:原来向量检索这件事,根本不需要搞的那么复杂。

pgvector
PostgreSQL原生向量支持

1. 为什么选pgvector

2. 环境搭建与配置

3. 向量类型与索引选型

4. RAG中的CRUD实战

5. 性能调优与避坑

6. 选型对比与总结

一体化方案

ACID事务保证

安装与启用

版本匹配

vector类型

HNSW索引

IVFFlat索引

混合查询SQL

批量插入优化

维度权衡

连接池配置

vs 专用向量库

适用场景分析

文字目录:

  1. 为什么选pgvector:一体化方案与ACID诱惑
  2. 环境搭建与配置:别让第一步就翻车
  3. 向量类型与索引选型:HNSW和IVFFlat的生死抉择
  4. RAG中的CRUD实战:SQL才是向量检索的终极浪漫
  5. 性能调优与避坑:维度、批量与连接池
  6. 选型对比与总结:你的瑞士军刀,但不是万能药

嗨,大家好呀,我是你的老朋友精通代码大仙。接下来我们一起学习 《大模型RAG生成式AI开发实战》147.[第15章 向量数据库选型] pgvector方案:PostgreSQL原生向量支持

“学编程就像过日子,能一个锅炒熟的菜,就别把厨房堆满电器。”

做RAG开发的新手同学们,我发现你们特别爱折腾。业务数据存在PostgreSQL里,向量数据呢?非得再搞一个Milvus、Pinecone或者Weaviate。结果呢?两边数据同步全靠业务代码硬撑,事务一致性不存在,半夜告警像催命,运维同学想打人。你就想做一个企业内部知识库问答,或者一个带语义搜索的电商小程序,真的有必要把架构图画的像航天飞机一样复杂吗?

今天咱们就来聊聊pgvector这个方案。它不搞颠覆,它就是让你的老朋友PostgreSQL长出了向量的翅膀。读完这篇,你会少踩至少十个生产环境的深坑。


1. 为什么选pgvector:一体化方案与ACID诱惑

很多新手同学对“专业向量数据库”有一种盲目的崇拜。觉得既然要做语义检索,那就必须上专用库,Postgres这种老家伙只配存存订单、用户表。但pgvector的出现,直接把这种认知按在地上摩擦。

pgvector是PostgreSQL的一个开源扩展。装上它,你的Postgres表里就能直接存 vector(1536) 这种类型,能建向量索引,能执行 ORDER BY embedding <=> query_embedding 这种相似度排序。换句话说,你的业务元数据、文档原文、标签、权限、向量 embeddings,全部可以在一个数据库里解决。

这带来的好处是颠覆性的。你再也不用在Python代码里维护两套连接池,不用搞什么分布式事务补偿,更不用写一堆胶水代码去同步两边数据。

传统方案
数据割裂

PostgreSQL
业务数据

Milvus
向量数据

应用层同步
代码复杂
一致性难保证

pgvector方案
一体化

PostgreSQL
业务数据+向量

单事务保证
单连接池
单查询计划

我见过太多团队在这个地方栽跟头。最典型的错误做法,就是“双写模式”。用户修改了一篇文档标题,你的代码先更新Postgres里的 documents 表,然后异步发个消息去更新Milvus里的向量。听起来很美好,对吧?分布式嘛,解耦嘛。

但坑就在这里。

网络抖动一下,Postgres更新成功了,消息队列丢了一条,Milvus里的老向量没删掉。用户搜关键词,召回的还是旧标题的向量,点进去内容却对不上。RAG系统拿这个旧向量大模型做参考,生成的答案直接“胡说八道”。你查半天,发现是两边数据不同步。

还有更隐蔽的。新手喜欢把用户信息存在Postgres,向量存在专用库。查询的时候,先从向量库搜出Top 10的ID,再拿这10个ID去Postgres里查详情。结果呢?向量库返回的ID,在Postgres里可能早就被逻辑删除了。你拿到8条有效数据,2条空值,RAG上下文构建得稀碎,模型输出质量能高才怪。

更有甚者,为了同步两边数据,在代码里手写重试逻辑,try-catch套了三层,日志打满一屏幕,最终一致性全靠“玄学”。运维半夜被叫起来修数据,发现向量库里有一堆“幽灵向量”,根本找不到对应的业务记录。这种痛苦,谁经历过谁知道。

pgvector的核心优势,就是把向量数据重新拉回到关系模型的怀抱里。

看这段正确的表设计:

CREATE TABLE documents (
    id bigserial PRIMARY KEY,
    title text NOT NULL,
    content text,
    author_id bigint REFERENCES users(id),
    status varchar(20) DEFAULT 'active',
    created_at timestamp DEFAULT now(),
    embedding vector(1536)
);

CREATE INDEX idx_docs_embedding ON documents 
USING hnsw (embedding vector_cosine_ops);

看到没?embedding 就是表里的一个普通字段,像 titlecontent 一样自然。当用户删除一篇文档时:

BEGIN;
UPDATE documents SET status = 'deleted', embedding = NULL WHERE id = 123;
DELETE FROM user_favorites WHERE doc_id = 123;
COMMIT;

一个事务,要么全成功,要么全回滚。不存在Postgres提交了、向量没更新的情况。这就是ACID的力量,是业务系统最基础也最可靠的保证。

而且,你的查询可以长这样:

SELECT title, content, 1 - (embedding <=> %s) AS similarity
FROM documents
WHERE status = 'active'
  AND author_id = 456
ORDER BY embedding <=> %s
LIMIT 10;

元数据过滤和向量相似度排序,在同一个SQL里完成。PostgreSQL的查询优化器会自己决定:是先走B-tree索引过滤 statusauthor_id,再走向量索引取TopK,还是反过来。这种级别的融合,是任何外部向量库都给不了的。

少一个组件,就少一份运维噩梦。pgvector不是来取代所有专用向量库的,但它让绝大多数RAG场景的数据架构,回归到了最简单的样子。


2. 环境搭建与配置:别让第一步就翻车

听起来很基础,对吧?但pgvector的搭建,新手能踩的坑比你想象的多。版本匹配、扩展启用、权限配置,每一步都有人中招。

第一大坑:版本不匹配。你在Ubuntu上 sudo apt install postgresql-14-pgvector,但你的PostgreSQL跑的是15。装完一重启,扩展加载失败,日志里一堆错误,你满世界搜解决方案,结果发现包名就错了。

第二大坑:装完扩展,忘了执行 CREATE EXTENSION vector;。直接建表 CREATE TABLE t (e vector(768));,报错提示类型“vector”不存在。新手当场懵圈,以为安装失败了,其实只是把扩展当成插件,没启用而已。

第三大坑:直接用默认配置跑生产。PostgreSQL的默认 shared_buffers 可能只有128MB,跑向量索引构建时,内存分配不够,速度奇慢。或者在一个小云服务器上,硬要给百万级768维向量建HNSW索引,结果建到一半,OOM Killer登场,Postgres进程被系统干掉,数据库连接全断。

还有些同学,本地开发用Docker一把梭,到了生产环境要部署时傻眼了,不知道怎么去配一个带pgvector的Postgres实例,结果各种编译报错,依赖缺失, gcc、postgresql-server-dev 没装,扩展编译到一半卡住。

第一步,确认版本。pgvector的发布版本和PostgreSQL的大版本是绑定的。用Docker最省心:

docker run -d \
  -e POSTGRES_PASSWORD=yourpassword \
  -p 5432:5432 \
  ankane/pgvector:latest

如果你用本地安装,确保包名里的数字和你 psql --version 看到的一致。如果是源码编译,先装好 postgresql-server-dev-XXbuild-essential

第二步,进数据库,启用扩展。这是仪式感,也是必须步骤:

CREATE EXTENSION IF NOT EXISTS vector;

执行完这一步,你的数据库才算真正拥有了向量能力。别忘了检查:SELECT * FROM pg_extension WHERE extname = 'vector';

第三步,配置参数。向量运算和索引构建是吃内存的。建议至少把 shared_buffers 调到内存的25%左右,work_mem 根据并发度适当调高。如果是专门跑向量检索的实例,maintenance_work_mem 可以设大一些,加快索引创建速度。比如你有16G内存,可以设:

ALTER SYSTEM SET shared_buffers = '4GB';
ALTER SYSTEM SET maintenance_work_mem = '1GB';
SELECT pg_reload_conf();

建表时,养成好习惯,显式指定维度:

CREATE TABLE items (
    id bigserial PRIMARY KEY,
    content text,
    embedding vector(1536)
);

这里的 1536 是维度。如果你用的是OpenAI的 text-embedding-3-small,可能是1536维;如果用 text-embedding-3-large,可能是3072维。一定要和你的模型输出对齐,否则插入时直接报错:维度不匹配。

环境是地基,别在第一步就埋雷。pgvector的门槛不在技术难度,而在细心和版本意识。


3. 向量类型与索引选型:HNSW和IVFFlat的生死抉择

pgvector主要提供两种索引策略:IVFFlat(倒排文件扁平索引)和HNSW(层次化可导航小世界图索引)。选哪个?怎么配参数?这是新手最头疼的部分。

新手的第一反应往往是:听说HNSW速度快,那就全部HNSW!于是不管数据量、不管内存、不管场景,上来就:

CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);

然后在2核4G的小服务器上,插入百万级768维向量,建索引时内存直接爆满。因为HNSW的内存开销大约是原始数据的2倍左右。百万条768维向量,原始数据约3GB,HNSW索引可能要6GB以上。小机器根本扛不住。

还有人用IVFFlat,但参数随便设:

CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 10);

百万数据只分10个聚类列表。这意味着每次近似查询,只能排除少量无关列表,剩下的90%数据还是要扫。查询速度跟全表扫描没太大区别,索引起了个寂寞。

另外,距离度量函数选错也是重灾区。做文本语义相似度,本来应该用余弦相似度 vector_cosine_ops,结果新手照搬示例用了欧氏距离 vector_l2_ops。虽然在高维归一化向量上差距不大,但概念错了,后续调优全跑偏。内积 vector_ip_ops 什么时候用?新手更是一头雾水。

先上决策图:

内存充足
数据量<1000万
追求高召回

内存紧张
数据量极大
容忍轻微精度损失

索引选型决策

数据规模与内存

HNSW
vector_cosine_ops

IVFFlat
合理设置lists

ef_search: 64~200

m: 16~32

lists ≈ rows/1000

probes: 10~100

具体怎么选?

HNSW:查询性能强,召回率高,但构建慢、内存占用大。适合绝大多数中小型RAG应用。推荐参数:

CREATE INDEX ON documents 
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

查询时调整 ef_search

SET hnsw.ef_search = 100;
SELECT * FROM documents ORDER BY embedding <=> %s LIMIT 10;

ef_search 越大,召回越准,但越慢。对RAG来说,漏召比慢更致命,建议设到100以上。m 控制图的连接度,默认16够用;数据量极大或需要更高召回,可以调到32甚至64。

IVFFlat:构建快,内存占用小,适合大规模数据或资源受限环境。关键是 lists 参数:

CREATE INDEX ON documents 
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);  -- 假设你有10万条数据

经验公式:lists 通常设为数据量的平方根,或数据量除以1000。查询时通过 probes 控制精度:

SET ivfflat.probes = 10;
SELECT * FROM documents ORDER BY embedding <=> %s LIMIT 10;

probes 越大,扫描的聚类列表越多,召回越高。

距离函数怎么选?

  • vector_cosine_ops:最常用,适合语义相似度,对向量长度不敏感。做RAG文本检索,无脑选它。
  • vector_l2_ops:欧氏距离,适合物理空间距离、图像特征等。如果embedding已经归一化,和余弦结果接近。
  • vector_ip_ops:内积,适合某些特定模型训练时采用内积损失的场景。一般RAG用不到。

对于RAG场景,我的一般建议是:如果单机内存足够,无脑HNSW;如果数据量过千万,或者你就是没钱买大内存机器,用IVFFlat,仔细调 listsprobes

没有银弹索引,只有场景匹配。HNSW像跑车,IVFFlat像省油家用车,看路况选,别闭着眼睛踩油门。


4. RAG中的CRUD实战:SQL才是向量检索的终极浪漫

说一千道一万,代码才是王道。在RAG应用里,怎么用pgvector完成文档的增删改查?怎么把向量检索和业务过滤揉在一起?

新手最容易犯的架构错误,就是“分段式查询”。他们的代码逻辑是这样的:

# 第一步:去向量库搜
vector_ids = vector_db.search(query_embedding, top_k=50)

# 第二步:拿ID去关系库过滤
docs = postgres.query(
    "SELECT * FROM docs WHERE id = ANY(%s) AND status='active'",
    [vector_ids]
)

# 第三步:可能还不够50条,再补搜...

这种写法问题太大了。第一,两次网络往返,延迟翻倍。第二,向量库召回的50条里,可能只有3条符合 status='active' 和业务过滤条件。你设置 top_k=50,实际有效数据可能不到10条,RAG上下文被严重稀释。第三,代码复杂度指数级上升,维护起来要了老命。

还有一种错误,是在应用层做相似度计算。把整张表的向量读到内存里,用Python的 numpy 算余弦相似度。数据量小的时候自欺欺人,数据量大了直接内存爆炸,查询慢到用户怀疑人生。

记住这句话:在pgvector里,向量检索就是SQL的一部分。

插入文档并生成向量:

INSERT INTO documents (title, content, embedding)
VALUES (
    'pgvector入门指南',
    '本文介绍如何在PostgreSQL中使用pgvector...',
    '[0.0023, -0.0112, 0.0333, ...]'::vector(1536)
);

实际项目中,embedding通常是在Python里调用模型生成的,然后通过参数化查询插入。千万不要自己拼SQL字符串,防止注入不说,性能也差。

真正的杀手锏,是混合查询。假设我们要做一个“最近7天内、属于AI分类、且与用户问题语义最相关”的文档检索:

SELECT 
    id,
    title,
    content,
    1 - (embedding <=> %s) AS cosine_similarity
FROM documents
WHERE 
    category = 'AI'
    AND status = 'published'
    AND created_at >= now() - interval '7 days'
ORDER BY embedding <=> %s
LIMIT 10;

看到没?WHERE 条件负责业务过滤,ORDER BY embedding <=> %s 负责向量排序。PostgreSQL优化器会生成一个高效的执行计划:可能先走 categorycreated_at 的B-tree索引,把数据过滤到很小的一个集合,再在这个集合上做向量距离排序。

如果你担心这种混合查询的向量索引不被使用,可以用 EXPLAIN ANALYZE 看看执行计划。通常情况下,当过滤条件能筛掉绝大部分数据时,优化器会优先走B-tree;当过滤后数据量仍然很大,才会走向量索引。这种智能决策,是外部向量库永远无法给予你的。

更新和删除也一样简单:

-- 更新文档内容,同时更新向量
UPDATE documents 
SET content = '更新后的内容', 
    embedding = '[...]'::vector(1536),
    updated_at = now()
WHERE id = 123;

-- 软删除,向量置空,自然不会再被检索到
UPDATE documents 
SET status = 'archived', 
    embedding = NULL 
WHERE id = 123;

不需要任何分布式事务,不需要消息队列,不需要最终一致性。简单又可靠。

用户提问

Embedding模型

构造混合查询SQL

PostgreSQL
pgvector

向量排序+业务过滤
单事务完成

TopK结果

Prompt组装

大模型生成回答

SQL的存在不是为了让你写得更复杂,而是把关系数据和向量距离真正融合在一个查询计划里。这才是RAG该有的样子,优雅且高效。


5. 性能调优与避坑:维度、批量与连接池

很多新手把pgvector装好了、表建好了、索引也建了,但一到生产环境就慢、就卡、就崩。为什么?因为维度没权衡、插入没批量、连接没池化。

维度灾难。OpenAI默认吐1536维,有些同学不管三七二十一,直接 vector(1536)。但你真的需要1536维吗?对于大多数中文文档检索场景,经过降维到384维甚至256维,检索效果损失不到2%,但磁盘空间省掉75%,内存占用和查询速度提升数倍。新手不知道可以降维,硬扛高维度,小服务器直接被拖垮。

单条插入。我见过这样的代码:

for doc in docs:
    emb = get_embedding(doc.text)  # 调API
    cur.execute(
        "INSERT INTO docs (content, embedding) VALUES (%s, %s)",
        (doc.text, emb)
    )
    conn.commit()  # 每条都commit!

10万条数据,commit 10万次。WAL日志疯狂刷盘,磁盘IO直接拉满,插入速度从每小时10万条降到每小时几千条。而且每次调embedding API都是一次网络请求,串行执行慢得让人想砸键盘。

连接风暴。Python脚本里每次查询都 psycopg2.connect(...),查完就关。并发一高,PostgreSQL的连接数瞬间被打满,后面来的请求全被拒。pgvector的查询虽然不慢,但创建连接的开销足以让系统瘫痪。

从不VACUUM。向量表更新频繁,旧版本堆积,表空间膨胀。新手从来不跑 VACUUM ANALYZE,查询计划越来越不准,索引也变得越来越低效。

降维。在把向量存进去之前,考虑用PCA或者更简单的办法,选一个支持低维输出的embedding模型。比如OpenAI的 text-embedding-3-small 可以指定 dimensions=256。如果已经生成了高维向量,也可以在应用层做简单降维后再存储。省下来的磁盘和内存,足够你再扛十倍数据量。

批量插入。这是最基本也最有效的优化:

# 先批量生成向量(如果有本地模型)
embeddings = model.encode([doc.text for doc in docs])

# 再批量插入,一次commit
data = [(doc.text, emb.tolist()) for doc, emb in zip(docs, embeddings)]
cur.executemany(
    "INSERT INTO docs (content, embedding) VALUES (%s, %s)",
    data
)
conn.commit()

更进一步,如果数据量极大,用 COPY 命令从CSV或Binary流导入,速度比 INSERT 快一个数量级。

连接池。生产环境绝对不要用裸连接。Python里用 psycopg2.pool 或者 SQLAlchemy 的连接池。配置 pool_sizemax_overflow,让连接复用。如果是微服务架构,中间加一层PgBouncer,把短连接变长连接,数据库压力骤降。

定期维护。养成习惯,在业务低峰期执行:

VACUUM ANALYZE documents;

VACUUM 回收死元组占用的空间,ANALYZE 更新表的统计信息,让优化器能选择最优的执行计划。对于频繁更新的向量表,这步不能省。

还有一个隐藏的坑:HNSW索引在批量导入大量数据时,逐行更新索引的开销巨大。建议先建表、导数据、最后统一建索引,而不是每插一条就更新索引。导入速度会快很多。如果必须在线导入,可以先把索引删掉,批量导完后再重建。

性能不是喊出来的,是批量插入、合理降维、连接池化和日常维护堆出来的。魔鬼藏在细节里,高手和菜鸟的差距就在这。


6. 选型对比与总结:你的瑞士军刀,但不是万能药

说了这么多pgvector的好,我得泼一盆冷水:它不是万能的。知道什么时候用它,什么时候必须上专用向量库,才是真正的架构师思维。

新手最容易陷入两个极端。要么“pgvector万能论”,什么场景都硬上,结果十亿级向量单机撑不住,查询延迟飙到秒级,哭着来找我。要么“pgvector垃圾论”,几十万数据就要上Milvus集群,三副本、coordinator、data node、query node、etcd、对象存储,运维成本比业务代码还高。结果QPS就几十,集群CPU常年5%,纯粹是为了复杂而复杂。

我们从几个维度理性对比:

30% 25% 20% 15% 10% RAG向量库选型考量权重 已有PG基础设施 数据规模<1000万 强一致性需求 团队SQL能力 运维成本控制

数据规模

  • 百万级以下:pgvector单机毫无压力,首选。
  • 千万级:pgvector依然能打,但需要好的硬件和调优。
  • 亿级以上:考虑专用库,或pgvector加分库分表/分区策略。
  • 十亿级以上:直接上Milvus、Pinecone这类为大规模设计的系统。

一致性要求
如果你的RAG应用是金融、医疗、内部核心知识库,数据一致性要求极高,业务数据和向量必须强一致。pgvector是唯一简单正确的选择。专用向量库大多是最终一致性,跨系统同步总有延迟。

运维成本
已经有PostgreSQL基础设施的团队,引入pgvector的边际成本接近零。而引入Milvus,你需要多维护一套K8s或至少一组独立服务,监控、告警、备份、扩容,全是成本。

查询复杂度
pgvector擅长“向量检索 + 强关联业务过滤”。如果你的查询主要是纯向量搜索,且需要非常复杂的向量聚类、向量分类、多向量融合检索,专用库的工具链可能更成熟。

成本
Pinecone按用量收费,数据量大了账单惊人。Milvus开源但服务器成本不低。pgvector开源免费,跑在你现有的Postgres上,成本最可控。

对于大多数企业内部的RAG系统、文档问答、电商语义搜索、个人知识库,pgvector就是最优解。它让你的架构保持简单,让团队把精力集中在业务和大模型调优上,而不是折腾基础设施。

技术选型选的不是最强的,而是最合适的。pgvector是绝大多数RAG场景的那把瑞士军刀,锋利、顺手、随时可用。但如果你要砍参天大树,记得换电锯。


写在最后

写到这儿,我突然想起自己当年第一次做语义检索的时候。那时候还没有pgvector,为了存个向量,我把Redis、Elasticsearch、Faiss试了个遍,代码写得像意大利面条,凌晨三点还在修数据不同步的Bug。后来pgvector出来了,我第一反应是:“就加了个扩展?能行吗?” 结果一试,真香。

编程这条路,说到底就是一个从复杂回归简单的过程。我们学那么多框架、那么多中间件,最终目的不是为了把架构图画得多么宏伟,而是为了解决实际问题。pgvector最让我欣赏的,就是它尊重了这种简单。它没有发明一套新的API,没有创造一种新的查询语言,它只是让PostgreSQL,这个陪伴我们多年的老朋友,学会了一项新技能。

如果你现在正站在RAG开发的十字路口,看着五花八门的向量数据库不知如何选择,我的建议是:先试试pgvector。用它搭一个原型,跑通你的业务流。你会发现,很多你以为必须引入的复杂度,其实根本不存在。

编程之路不易,但每一步成长都算数。保持好奇,持续学习,你也一定能在技术的浪潮里找到属于自己的节奏。相信自己,你比想象中更强大。咱们下回见!

关注私信备注:“资料代找获取”,全网计算机学习资料代找:例如:
《课程:2026 年多模态大模型实战训练营》
《课程:AI 大模型工程师系统课程 (22 章完整版 持续更新)》
《课程:AI 大模型系统实战课第四期 (2026 年开课 持续更新)》
《课程:2026 年 AGI 大模型系统课 23 期》
《课程:2026 年 AGI 大模型系统课 21 期》
《课程:AI 大模型实战课 8 期 (2026 年 2 月最新完结版)》
《课程:AI 大模型系统实战课三期》
《课程:AI 大模型系统课程 (2026 年 2 月开课 持续更新)》
《课程:AI 大模型全阶课程 (2025 年 12 月开课 2026 年 6 月结课)》
《课程:AI 大模型工程师全阶课程 (2025 年 10 月开课 2026 年 4 月结课)》
《课程:2026 年最新大模型 Agent 开发系统课 (持续更新)》
《课程:LLM 多模态视觉大模型系统课》
《课程:大模型 AI 应用开发企业级项目实战课 (2026 年 1 月开课)》
《课程:大模型智能体线上速成班 V2.0》
《课程:Java+AI 大模型智能应用开发全阶课》
《课程:Python+AI 大模型实战视频教程》
《书籍:软件工程 3.0: 大模型驱动的研发新范式.pdf》
《课程:人工智能大模型系统课 (2026 年 1 月底完结版)》
《课程:AI 大模型零基础到商业实战全栈课第五期》
《课程:Vue3.5+Electron + 大模型跨平台 AI 桌面聊天应用实战 (2025)》
《课程:AI 大模型实战训练营 从入门到实战轻松上手》
《课程:2026 年 AI 大模型 RAG 与 Agent 智能体项目实战开发课》
《课程:大模型训练营配套补充资料》

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐