饮墨

子安饮墨馀三斗,留与卿儿作赋来

用 pgvector 把 PostgreSQL 变成向量数据库:AI 应用落地最省心的方案

痛点

你在做 RAG、语义搜索或推荐系统,需要一个向量数据库。调研一圈:Pinecone 要钱、Milvus 太重、Chroma 只适合原型。团队已经有 PostgreSQL 集群在跑,运维体系成熟,监控备份一套全的。这时候再引入一个独立的向量数据库,意味着:多一套运维、多一份数据同步、多一个故障点。

核心矛盾:AI 应用需要向量检索,但你不想为了这一个能力再养一套基础设施。

pgvector 的答案很直接——给 PostgreSQL 装个扩展,原地升级为向量数据库。事务、权限、备份、高可用全部复用现有体系,零额外运维成本。


方案概览

pgvector 是 PostgreSQL 的开源扩展,核心能力:

能力 说明
向量存储 支持最高 16000 维向量
索引算法 IVFFlat(适合中小数据集)、HNSW(适合大规模高性能场景)
距离函数 L2 欧氏距离、余弦相似度、内积
SQL 原生 向量查询就是普通 SQL,和业务数据 JOIN、过滤无缝结合
事务安全 向量写入和业务写入在同一个事务里,数据一致性有保障

适用场景:百万到千万级向量、需要和结构化数据联合查询、团队已有 PG 运维经验。


实操步骤

第 1 步:安装 pgvector

Ubuntu/Debian(PostgreSQL 16):

# 安装扩展包
sudo apt install postgresql-16-pgvector

# 进入 psql 启用扩展
psql -U postgres -d your_database -c "CREATE EXTENSION IF NOT EXISTS vector;"

Docker 一行搞定:

docker run -d --name pgvector \
  -e POSTGRES_PASSWORD=your_password \
  -p 5432:5432 \
  pgvector/pgvector:pg16

验证安装:

SELECT * FROM pg_extension WHERE extname = 'vector';
-- 看到一行记录说明已启用

第 2 步:建表 + 存储向量

以一个文档语义搜索场景为例:

-- 创建文档表,embedding 列存 1536 维向量(OpenAI text-embedding-3-small 输出维度)
CREATE TABLE documents (
    id BIGSERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    embedding vector(1536),
    created_at TIMESTAMPTZ DEFAULT NOW()
);

写入向量数据(Python 示例):

import psycopg2
from openai import OpenAI

client = OpenAI()
conn = psycopg2.connect("postgresql://postgres:your_password@localhost/your_database")

def embed_and_store(title: str, content: str):
    # 生成 embedding
    resp = client.embeddings.create(
        model="text-embedding-3-small",
        input=content
    )
    embedding = resp.data[0].embedding  # List[float], 1536 维

    # 写入 PG
    with conn.cursor() as cur:
        cur.execute(
            "INSERT INTO documents (title, content, embedding) VALUES (%s, %s, %s)",
            (title, content, embedding)
        )
    conn.commit()

# 使用
embed_and_store(
    "K8s Pod 调度原理",
    "Kubernetes 调度器通过 Predicates 过滤不满足条件的节点..."
)

第 3 步:创建 HNSW 索引

数据量超过 10 万条后,暴力扫描太慢,必须建索引:

-- HNSW 索引(推荐,查询快、召回率高)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);

-- 调整查询时的搜索范围(越大越准,越慢)
SET hnsw.ef_search = 100;

IVFFlat vs HNSW 选型:

指标 IVFFlat HNSW
构建速度 快(需要数据先入库) 慢(但支持增量插入)
查询延迟 中等 低(通常 <10ms)
召回率 依赖 lists 参数 高(>95%)
内存占用 较低 较高
适合场景 数据不频繁更新 实时写入 + 查询

生产环境推荐 HNSW,除非内存紧张。

第 4 步:语义搜索查询

-- 查询最相似的 5 篇文档(余弦距离)
SELECT id, title, 1 - (embedding <=> $1::vector) AS similarity
FROM documents
WHERE created_at > NOW() - INTERVAL '30 days'  -- 结合业务条件过滤
ORDER BY embedding <=> $1::vector
LIMIT 5;

Python 完整查询:

def semantic_search(query: str, top_k: int = 5):
    # 生成查询向量
    resp = client.embeddings.create(
        model="text-embedding-3-small",
        input=query
    )
    query_embedding = resp.data[0].embedding

    with conn.cursor() as cur:
        cur.execute("""
            SELECT id, title, 1 - (embedding <=> %s::vector) AS similarity
            FROM documents
            ORDER BY embedding <=> %s::vector
            LIMIT %s
        """, (query_embedding, query_embedding, top_k))
        return cur.fetchall()

# 使用
results = semantic_search("如何排查 Pod 启动失败")
for doc_id, title, score in results:
    print(f"[{score:.3f}] {title}")

避坑指南

坑 1:不建索引就上生产

pgvector 默认走全表扫描(Seq Scan),10 万条以上查询延迟飙升。

解决: 数据量 > 1 万就建 HNSW 索引。建索引期间表不锁写,但会消耗大量内存和 CPU,建议在低峰期执行:

-- 限制建索引时的内存使用
SET maintenance_work_mem = '2GB';
CREATE INDEX CONCURRENTLY ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);

坑 2:向量维度选错,后期改不了

vector(1536) 一旦建表,维度就固定了。换模型(比如从 1536 维换到 3072 维)意味着要新建列或新建表。

解决: 建表时明确锁定 Embedding 模型,记在文档里。如果未来可能换模型,可以多建一列预留:

ALTER TABLE documents ADD COLUMN embedding_v2 vector(3072);

HNSW 索引的查询精度和速度由 ef_search 控制。默认值 40 可能召回率不够。

解决: 根据业务需求调整: - 要求高召回(如 RAG):SET hnsw.ef_search = 200; - 要求低延迟(如实时推荐):SET hnsw.ef_search = 50;

可以用已知正确答案的测试集跑一轮 benchmark,找到延迟和召回的平衡点。


生产部署建议

  1. 内存规划:HNSW 索引常驻内存,1000 万条 1536 维向量 ≈ 60GB 索引内存。shared_buffers 至少给总内存的 25%,确保索引能缓存住。

  2. 监控指标:关注 pg_stat_user_indexes 中 HNSW 索引的 idx_scanidx_tup_read,确认查询走了索引而非 Seq Scan。

  3. 备份无感知:pgvector 数据就是普通 PG 表,pg_dump、pg_basebackup、流复制全部原生支持,不需要额外备份策略。

  4. 高可用:主从复制的从库可以直接分担向量查询流量,读写分离和传统业务一模一样。


总结

维度 pgvector 独立向量数据库
运维成本 零额外(复用 PG 体系) 多一套集群
数据一致性 事务保证 需要同步机制
联合查询 SQL JOIN 原生支持 跨库查询复杂
性能上限 千万级(单机),更大需分区 亿级(分布式)
学习成本 会 SQL 就会用 新 API、新概念

结论: 如果你的向量规模在千万级以下,且团队已有 PostgreSQL 基础设施,pgvector 是 ROI 最高的选择。不加服务器、不加运维、不加数据同步——装个扩展,写条 SQL,AI 应用的向量检索就有了。

别为了追新技术给自己找麻烦。用好手里的工具,才是工程师的核心竞争力。

您还没有登录,请登录后发表评论。