跳到主要内容

pgvector 扩展

问题

PostgreSQL 的 pgvector 扩展是什么?如何用它实现向量搜索?

答案

一、pgvector 简介

pgvector 是 PostgreSQL 的开源向量搜索扩展,让 PostgreSQL 原生支持向量存储和相似度搜索。它的最大优势是不需要引入额外的向量数据库,直接复用现有的 PostgreSQL 基础设施。

-- 安装扩展
CREATE EXTENSION vector;

二、为什么选择 pgvector

优势说明
零额外运维复用现有 PostgreSQL,不引入新组件
SQL 原生用标准 SQL 进行向量搜索
混合查询向量搜索 + 标量过滤在同一条 SQL 中完成
事务支持ACID 事务保证数据一致性
JOIN 能力向量搜索结果可以 JOIN 其他表

适合中小规模(百万级以内向量)、已有 PostgreSQL 基础设施、需要混合查询的场景。

三、基本使用

创建表

-- 创建带向量字段的表
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
category VARCHAR(64),
-- vector(1536) 表示 1536 维向量(OpenAI text-embedding-3-small 的维度)
embedding vector(1536),
created_at TIMESTAMP DEFAULT NOW()
);

插入数据

-- 插入向量数据
INSERT INTO documents (title, content, category, embedding)
VALUES (
'PostgreSQL 入门',
'本文介绍 PostgreSQL 的基本使用...',
'database',
'[0.23, -0.15, 0.87, ..., 0.42]' -- 1536 维向量
);

相似度搜索

-- 余弦距离搜索(<=> 操作符)
-- 返回与查询向量最相似的 10 条记录
SELECT id, title, 1 - (embedding <=> '[0.1, 0.2, ...]') AS similarity
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, ...]'
LIMIT 10;

-- L2 距离搜索(<-> 操作符)
SELECT id, title
FROM documents
ORDER BY embedding <-> '[0.1, 0.2, ...]'
LIMIT 10;

-- 内积搜索(<#> 操作符,取负值)
SELECT id, title
FROM documents
ORDER BY embedding <#> '[0.1, 0.2, ...]'
LIMIT 10;
距离操作符
操作符含义排序方式
<->L2 距离值越小越相似
<=>余弦距离值越小越相似(1 - 余弦相似度)
<#>负内积值越小越相似

混合查询(向量 + 标量过滤)

-- 在特定分类下搜索最相似的文档
SELECT id, title, 1 - (embedding <=> $1) AS similarity
FROM documents
WHERE category = 'database'
AND created_at > '2024-01-01'
ORDER BY embedding <=> $1
LIMIT 10;

这是 pgvector 相比专用向量数据库的核心优势——向量搜索和标量过滤在一条 SQL 中完成,无需应用层二次过滤。

四、索引

pgvector 支持两种向量索引:

IVFFlat 索引

-- 创建 IVFFlat 索引(需要先有数据)
CREATE INDEX ON documents
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100); -- 聚类数量,推荐 sqrt(行数)

查询时设置探查数:

-- 搜索时探查的聚类数(越大越精确,越慢)
SET ivfflat.probes = 10;

HNSW 索引(推荐)

-- 创建 HNSW 索引(0.5.0+ 版本支持。可在空表上创建)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

查询时设置搜索宽度:

SET hnsw.ef_search = 40;

索引对比

对比IVFFlatHNSW
建索引要求需要先有数据可在空表上创建
查询速度较快更快
召回率90~99%95~99%
建索引时间
内存占用
推荐场景数据量大、内存有限通用场景(推荐)

五、性能优化

1. 维度优化

如果业务不需要高维向量,可以降维减少存储和计算开销:

-- 使用 halfvec 半精度(float16,节省一半存储)
CREATE TABLE items (
id BIGSERIAL PRIMARY KEY,
embedding halfvec(768) -- 半精度向量
);

2. 分区表

-- 按分类分区,缩小搜索范围
CREATE TABLE documents (
id BIGSERIAL,
category VARCHAR(64),
embedding vector(1536)
) PARTITION BY LIST (category);

CREATE TABLE documents_tech PARTITION OF documents FOR VALUES IN ('tech');
CREATE TABLE documents_finance PARTITION OF documents FOR VALUES IN ('finance');

每个分区独立建向量索引,查询时自动裁剪分区。

3. 并行查询

-- 调大并行度
SET max_parallel_workers_per_gather = 4;

六、与 ORM 集成

Node.js(Prisma + pgvector)

// Prisma schema 中使用 Unsupported 类型
// 通过 raw SQL 进行向量操作
const results = await prisma.$queryRaw`
SELECT id, title, 1 - (embedding <=> ${embedding}::vector) as similarity
FROM documents
WHERE category = ${category}
ORDER BY embedding <=> ${embedding}::vector
LIMIT 10
`;

Python(SQLAlchemy + pgvector)

from pgvector.sqlalchemy import Vector
from sqlalchemy import Column, Integer, String

class Document(Base):
__tablename__ = "documents"
id = Column(Integer, primary_key=True)
title = Column(String)
embedding = Column(Vector(1536)) # pgvector 向量类型

# 搜索
from sqlalchemy import select

stmt = select(Document).order_by(
Document.embedding.cosine_distance(query_vector)
).limit(10)
results = session.execute(stmt).scalars().all()

七、pgvector vs 专用向量数据库

对比pgvectorMilvus/Qdrant
运维成本低(复用 PG)高(独立集群)
数据规模百万级十亿级
混合查询原生 SQL有限标量过滤
事务支持完整 ACID不支持
向量搜索性能中等极高
索引类型HNSW、IVFFlatHNSW、IVF、PQ 等
适合场景中小规模、已有 PG大规模向量搜索
选型建议
  • 数据量 < 100 万,已有 PostgreSQL → pgvector
  • 数据量 > 100 万,向量搜索是核心功能 → Milvus/Qdrant
  • 需要全文搜索 + 向量搜索 → Elasticsearch 或 PostgreSQL(全文 + pgvector)

常见面试问题

Q1: pgvector 的优势和劣势是什么?

答案

优势

  1. 零额外运维,复用 PostgreSQL
  2. SQL 原生,支持向量搜索 + 标量过滤 + JOIN
  3. 完整的 ACID 事务支持
  4. 社区活跃,更新频繁

劣势

  1. 大规模向量搜索性能不如专用向量数据库
  2. 索引类型有限(HNSW、IVFFlat)
  3. 分布式能力依赖 PostgreSQL 本身(Citus 等)
  4. 不适合十亿级别的超大规模场景

Q2: pgvector 的 HNSW 索引参数如何调优?

答案

两个关键参数:

参数作用推荐值增大的影响
m每个节点的连接数16~32召回率↑ 内存↑ 建索引慢↑
ef_construction建图搜索宽度64~200索引质量↑ 建索引慢↑

查询时的 hnsw.ef_search(默认 40):增大提高召回率但增加延迟。

调参流程:从默认值开始,用基准测试数据集评估 Recall 和 QPS,逐步调整。

Q3: pgvector 搜索结果如何获取相似度分数?

答案

-- 余弦距离转相似度:1 - 距离
SELECT id, title,
1 - (embedding <=> $1) AS cosine_similarity -- 0~1,越大越相似
FROM documents
ORDER BY embedding <=> $1
LIMIT 10;

-- L2 距离直接返回(越小越相似)
SELECT id, title,
embedding <-> $1 AS l2_distance
FROM documents
ORDER BY embedding <-> $1
LIMIT 10;

相关链接