跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

pgvector 文档

PostgreSQL 开源向量相似性检索基础扩展:涵盖 vector、halfvec、bit 与 sparsevec 数据类型,精确与近似最近邻搜索,以及 HNSW 与 IVFFlat 索引。

pgvector 是 PostgreSQL 生态中最基础的开源向量相似性检索扩展。它提供了核心的 vector、halfvec、bit 与 sparsevec 向量数据类型、距离操作符,以及内置的 HNSW 和 IVFFlat 索引访问方法。

与 vchord 的关系

vchord 直接构建在 pgvector 的数据类型(vector 与 halfvec)和距离操作符(<->、<#>、<=>)之上。无需修改现有的表结构或应用层 SQL,即可直接在现有的 pgvector 向量列上创建 vchord(vchordrq 或 vchordg)索引。

核心特性

  • 精确与近似最近邻检索(KNN / ANN):与 PostgreSQL 完整 ACID 事务、时间点恢复(PITR)、关系连接(JOIN)及谓词过滤无缝融合。
  • 多种向量数据表示:
    • 单精度浮点向量(vector,索引最高支持 2,000 维,无索引存储最高支持 16,000 维)
    • 半精度浮点向量(halfvec,索引最高支持 4,000 维)
    • 二值位向量(bit,索引最高支持 64,000 维)
    • 稀疏向量(sparsevec,最高支持 1,000 个非零元素、总维度高达 100 万维)
  • 六种距离度量:欧氏 L2 距离(<->)、内积(<#>)、余弦距离(<=>)、曼哈顿 L1 距离(<+>)、汉明距离(<~>)以及杰卡德距离(<%>)。
  • 迭代式索引扫描(Iterative Index Scans,0.8.0+):当带 WHERE 过滤条件导致候选集不足时,自动扩展 HNSW 或 IVFFlat 索引遍历范围以保证召回数量。

文档章节导航

通过 Pigsty、Docker、Linux 软件源、Homebrew 或源码编译安装 pgvector,启用扩展并执行向量写入与批量导入。

距离操作符、相似度计算、向量聚合函数、带 WHERE 条件的迭代索引扫描以及全文/BM25 混合检索。

HNSW 与 IVFFlat 索引构建与参数调优、并行建索引、进度监控,以及使用 vchord 突破内存瓶颈。

半精度(halfvec)、二值量化(bit + 精确重排)、稀疏向量(sparsevec)以及套娃(Matryoshka)子向量索引。

完整 SQL 函数与操作符速查表、GUC 参数、内存规划、执行计划排查与常见问题解答。

在现有的 pgvector 向量列上无缝添加 vchordrq 与 vchordg RaBitQ 索引,无需修改业务查询即可扩展至亿级规模。

1 - 安装与快速上手

在 PostgreSQL 14–18 上安装 pgvector 并运行第一个向量相似性查询。

安装方式

Pigsty / Linux 原生软件包(推荐)

Pigsty 为 Debian、Ubuntu 以及 RHEL/Rocky/AlmaLinux(x86_64 与 ARM64 架构)提供了针对 PostgreSQL 14–18 预编译的原生 pgvector(v0.8.2)软件包:

pig repo add pgdg pigsty -u
pig ext install pgvector

如果您同时需要磁盘友好的 RaBitQ 向量索引与原生 BM25 检索能力,可以一次性安装完整的 Vchord 套件:

pig ext install pgvector vchord vchord_bm25 pg_tokenizer

Docker 容器

直接启动官方 pgvector 容器镜像:

docker run -d \
  --name pgvector-demo \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  pgvector/pgvector:pg18

或者使用开箱即用的 Vchord 全家桶镜像(内置 pgvector、vchord、vchord_bm25 与 pg_tokenizer):

docker run -d \
  --name vchord-suite \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  tensorchord/vchord-suite:pg18-latest

Linux 官方软件源(PGDG APT / YUM)

macOS(Homebrew)

brew install pgvector

从源码编译安装(Linux / macOS)

请确保系统已安装 PostgreSQL 开发头文件(postgresql-server-dev-* 或 postgresql*-devel)、make 及 C 编译器:

cd /tmp
git clone --branch v0.8.2 https://github.com/pgvector/pgvector.git
cd pgvector
make
sudo make install
CPU 原生指令集优化

默认情况下,pgvector 的 Makefile 会在编译器支持时自动启用 -march=native 以最大化当前机器的 SIMD 吞吐性能。如果您需要构建跨不同代际 CPU 通用的可移植二进制包,请使用 make OPTFLAGS=""。


启用扩展

连接到目标数据库并启用 vector 扩展(需要在每个使用向量功能的数据库中执行一次):

CREATE EXTENSION IF NOT EXISTS vector;

查看当前安装的扩展版本:

SELECT extversion FROM pg_extension WHERE extname = 'vector';

升级 pgvector

在服务器上更新二进制包后,在数据库中执行以下命令升级 SQL 目录对象定义:

ALTER EXTENSION vector UPDATE;

快速上手

1. 创建包含向量列的表

创建一个包含 3 维单精度浮点(float32)向量的表:

CREATE TABLE items (
    id bigserial PRIMARY KEY,
    embedding vector(3)
);

也可以向已有表中添加向量列:

ALTER TABLE items ADD COLUMN embedding vector(3);

2. 插入、更新与删除向量

使用文本字面量格式 '[x1,x2,x3]' 插入向量:

INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');

使用 ON CONFLICT 执行 Upsert(插入或更新):

INSERT INTO items (id, embedding) VALUES (1, '[1,2,3]'), (2, '[4,5,6]')
ON CONFLICT (id) DO UPDATE SET embedding = EXCLUDED.embedding;

使用标准 SQL 更新或删除记录:

UPDATE items SET embedding = '[1,2,3]' WHERE id = 1;
DELETE FROM items WHERE id = 1;

3. 使用 COPY 批量导入

对于百万级以上的大规模数据集,强烈建议使用二进制 COPY 替代逐行 INSERT:

COPY items (embedding) FROM STDIN WITH (FORMAT BINARY);

4. 查询最近邻向量

按欧氏距离(L2)检索距离 '[3,1,2]' 最近的 5 条记录:

SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

接下来请阅读查询与过滤检索了解所有距离度量与过滤查询模式,或参阅HNSW 与 IVFFlat 索引了解如何加速大规模表上的近似检索。

2 - 查询与过滤检索

pgvector 的最近邻操作符、距离与相似度计算、向量聚合、带 WHERE 条件的迭代式索引扫描与混合检索。

距离操作符

pgvector 提供六种距离操作符,可用于排序(ORDER BY)与阈值过滤:

操作符 距离度量 支持的数据类型 说明
<-> 欧氏距离(L2) vector, halfvec, sparsevec ∑(ai−bi)2\sqrt{\sum (a_i - b_i)^2}
<#> 负内积(Negative Inner Product) vector, halfvec, sparsevec 返回 −∑aibi-\sum a_i b_i(因为 PostgreSQL 索引扫描仅支持升序 ASC 排序)
<=> 余弦距离(Cosine Distance) vector, halfvec, sparsevec 1−a⋅b∥a∥∥b∥1 - \frac{a \cdot b}{\|a\|\|b\|}(取值范围 [0, 2])
<+> 曼哈顿距离(L1) vector, halfvec, sparsevec (\sum
<~> 汉明距离(Hamming Distance) bit 两个位向量中不同比特位的数量(XOR 置位计数)
<%> 杰卡德距离(Jaccard Distance) bit (1 - \frac{
归一化向量建议

如果您的嵌入向量已经归一化为单位长度(例如 OpenAI text-embedding-3-* 或 BGE 模型输出),建议优先使用内积(<#>)而非余弦距离(<=>),以获得更高的 CPU 计算吞吐量。

最近邻检索示例

-- 按 L2 欧氏距离查询最近的 5 条记录
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

-- 按余弦距离查询最近的 5 条记录
SELECT * FROM items ORDER BY embedding <=> '[3,1,2]' LIMIT 5;

-- 按最大内积查询最相似的 5 条记录
SELECT * FROM items ORDER BY embedding <#> '[3,1,2]' LIMIT 5;

计算距离与相似度得分

在查询结果中同时返回距离或相似度数值:

-- 返回 L2 欧氏距离
SELECT id, embedding <-> '[3,1,2]' AS distance FROM items;

-- 返回真实内积(将负内积乘以 -1)
SELECT id, (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;

-- 返回余弦相似度(1 - 余弦距离)
SELECT id, 1 - (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;

距离阈值过滤查询

检索距离在指定半径内的所有记录:

SELECT * FROM items WHERE embedding <-> '[3,1,2]' < 5;

结合 ORDER BY 与 LIMIT 可直接利用 HNSW 或 IVFFlat 索引:

SELECT * FROM items
WHERE embedding <-> '[3,1,2]' < 5
ORDER BY embedding <-> '[3,1,2]'
LIMIT 5;
vchord 的原生球面范围查询

如果您的业务需要频繁按距离半径做范围过滤,vchord 提供了专用的 <<->> 球面操作符(WHERE embedding <<->> sphere('[3,1,2]'::vector, 5)),可直接在 vchordrq 或 vchordg 索引内部完成半径剪枝,而无需强制携带 ORDER BY ... LIMIT。详见 vchord 相似度范围过滤。


向量聚合函数

计算一组向量的均值中心(AVG)或逐元素累加和(SUM):

SELECT AVG(embedding) FROM items;

SELECT category_id, AVG(embedding) AS centroid
FROM items
GROUP BY category_id;

条件过滤(WHERE)与迭代式索引扫描

将向量相似性检索与结构化关系谓词结合:

SELECT * FROM items WHERE category_id = 123 ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

为过滤列建立索引

  1. 在过滤列上创建标准 B-tree 索引(适用于 category_id = 123 选择率极高、仅匹配极少行数的场景):
    CREATE INDEX ON items (category_id);
  2. 创建部分向量索引(Partial Index)(适用于仅按少数固定类别过滤的场景):
    CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WHERE (category_id = 123);
  3. 表分区(Partitioning)(适用于按租户或时间范围高频过滤的大表):
    CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id);

迭代式索引扫描(Iterative Index Scans,pgvector 0.8.0+)

默认情况下,近似向量索引扫描只会访问固定数量的候选集(hnsw.ef_search 或 ivfflat.probes)。如果 WHERE 过滤条件过滤掉了绝大部分候选行,最终返回的行数可能会少于 LIMIT。

自 pgvector 0.8.0 起,您可以开启迭代式索引扫描(Iterative Index Scans),让索引在候选结果不足时自动继续向后搜索,直到凑齐 LIMIT 条记录(或达到 max_scan_tuples / max_probes 上限):

-- 开启 HNSW 宽松顺序迭代扫描
SET hnsw.iterative_scan = relaxed_order;
-- 或使用 strict_order 严格保证跨迭代结果的精确距离顺序:
-- SET hnsw.iterative_scan = strict_order;

-- 开启 IVFFlat 宽松顺序迭代扫描
SET ivfflat.iterative_scan = relaxed_order;

使用 relaxed_order 时,返回结果的距离顺序可能存在轻微乱序,可通过外层 CTE 对最终的 LIMIT 条结果重排序:

WITH relaxed_results AS MATERIALIZED (
    SELECT id, embedding <-> '[3,1,2]' AS distance
    FROM items
    WHERE category_id = 123
    ORDER BY distance
    LIMIT 5
)
SELECT * FROM relaxed_results ORDER BY distance + 0;

控制迭代扫描开销上限

-- HNSW 迭代扫描最多访问的元组数(默认:20000)
SET hnsw.max_scan_tuples = 20000;

-- HNSW 记录已访问节点状态允许使用的 work_mem 倍数(默认:1)
SET hnsw.scan_mem_multiplier = 2;

-- IVFFlat 迭代扫描最多探测的倒排列表数
SET ivfflat.max_probes = 100;

您可以使用 倒数排序融合(Reciprocal Rank Fusion, RRF) 将 pgvector 语义检索与关键词全文检索结合。

结合 PostgreSQL 内置 tsvector

SELECT id, content FROM (
    SELECT id, content, 1.0 / (60 + RANK() OVER (ORDER BY embedding <=> '[3,1,2]')) AS score
    FROM items
    ORDER BY embedding <=> '[3,1,2]' LIMIT 20
    UNION ALL
    SELECT id, content, 1.0 / (60 + RANK() OVER (ORDER BY ts_rank_cd(textsearch, query) DESC)) AS score
    FROM items, plainto_tsquery('english', 'hello search') query
    WHERE textsearch @@ query
    ORDER BY ts_rank_cd(textsearch, query) DESC LIMIT 20
) searches
GROUP BY id, content
ORDER BY SUM(score) DESC
LIMIT 5;

结合 vchord_bm25 或 pg_bestmatch

如果您需要具备文档长度归一化与全局语料库 IDF 权重的标准 Okapi BM25 排序:

3 - HNSW 与 IVFFlat 索引

在 pgvector 中创建、调优与维护 HNSW 和 IVFFlat 近似最近邻索引,并与 vchord 进行对比。

默认情况下,pgvector 执行精确最近邻搜索(全表顺序扫描),具有 100% 的召回率。当表数据量增长至数万行以上时,可以通过创建近似最近邻(ANN)索引,以极小的召回率折中换取几个数量级的查询加速。

pgvector 内置了两种索引访问方法:

  • HNSW(Hierarchical Navigable Small World,分层可导航小世界图):多层近邻图结构。查询速度与召回率表现显著优于 IVFFlat,且无需预先训练步骤;代价是索引构建时间更长、内存占用更高。
  • IVFFlat(Inverted File with Flat Vectors,倒排文件索引):基于 K-means 聚类将向量划分到不同倒排列表。建索引速度更快、体积更小,但必须在表中已有数据的前提下创建,且相同延迟下的召回率低于 HNSW。
突破 HNSW 与 IVFFlat 的规模瓶颈

当数据集规模超过可用内存(例如千万级至十亿级向量),或者 HNSW 建索引耗时过长时,建议在 pgvector 基础上安装 vchord。vchord 提供的 vchordrq 与 vchordg 索引直接作用于 pgvector 的 vector 和 halfvec 列,通过 RaBitQ 量化压缩实现最高 100 倍建索引加速,并支持高效的磁盘/SSD 检索。


HNSW 索引

HNSW 索引构建了一个多层导航图。与 IVFFlat 不同,HNSW 没有聚类训练阶段,因此可以在空表上预先创建索引。

创建 HNSW 索引

根据查询语句中使用的距离操作符,选择对应的操作符类(Operator Class):

-- L2 欧氏距离 (<->)
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);

-- 内积 (<#>)
CREATE INDEX ON items USING hnsw (embedding vector_ip_ops);

-- 余弦距离 (<=>)
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);

-- L1 曼哈顿距离 (<+>)
CREATE INDEX ON items USING hnsw (embedding vector_l1_ops);

-- 位向量汉明距离 (<~>)
CREATE INDEX ON items USING hnsw (embedding bit_hamming_ops);

-- 位向量杰卡德距离 (<%>)
CREATE INDEX ON items USING hnsw (embedding bit_jaccard_ops);

HNSW 索引支持的最大维度上限:

  • vector:最高 2,000 维
  • halfvec:最高 4,000 维
  • bit:最高 64,000 维
  • sparsevec:最高 1,000 个非零元素

HNSW 构建参数

  • m(默认 16,范围 2–100):每个节点在每层图中的最大双向连接数。提高 m 可改善高内在维度数据集上的召回率,但会增加索引体积与构建耗时。
  • ef_construction(默认 64,范围 4–1000):建图时的动态候选列表大小,必须满足 ≥2×m\ge 2 \times m。
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)
WITH (m = 16, ef_construction = 64);

HNSW 查询参数

通过 hnsw.ef_search(默认 40,范围 1–1000)控制查询时的动态候选集大小。增大该值可提升召回率:

SET hnsw.ef_search = 100;

-- 或通过 SET LOCAL 仅对当前事务生效:
BEGIN;
SET LOCAL hnsw.ef_search = 100;
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
COMMIT;

加速 HNSW 索引构建

当 HNSW 图结构超出 maintenance_work_mem 容量时,建索引速度会急剧下降。在大表上创建 HNSW 索引前,请调大 maintenance_work_mem 与并行维护工作进程数:

SET maintenance_work_mem = '8GB';
SET max_parallel_maintenance_workers = 7; -- 加上 leader 共 8 个并行进程
说明

建议始终在完成 COPY 初始数据批量导入之后再创建 HNSW 索引。在生产环境中,请使用 CREATE INDEX CONCURRENTLY 以避免阻塞在线写入。


IVFFlat 索引

IVFFlat 索引利用 K-means 聚类将向量空间划分为 lists 个倒排分桶,查询时仅扫描距离查询向量最近的 ivfflat.probes 个分桶。

务必在导入数据后再创建 IVFFlat 索引

由于 IVFFlat 在 CREATE INDEX 期间计算 K-means 聚类中心,您必须在表中已有代表性数据之后再创建该索引。

创建 IVFFlat 索引

根据表的总行数设置 lists 参数:

  • 100 万行以内:rows / 1000
  • 超过 100 万行:sqrt(rows)
-- L2 欧氏距离 (<->)
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);

-- 内积 (<#>)
CREATE INDEX ON items USING ivfflat (embedding vector_ip_ops) WITH (lists = 100);

-- 余弦距离 (<=>)
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

-- 位向量汉明距离 (<~>)
CREATE INDEX ON items USING ivfflat (embedding bit_hamming_ops) WITH (lists = 100);

IVFFlat 索引支持的最大维度上限:

  • vector:最高 2,000 维
  • halfvec:最高 4,000 维
  • bit:最高 64,000 维

IVFFlat 查询参数

通过 ivfflat.probes(默认 1)设置每次查询探测的倒排列表数量,推荐初始值为 sqrt(lists):

BEGIN;
SET LOCAL ivfflat.probes = 10;
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
COMMIT;

索引构建进度监控与维护

监控建索引进度

在 CREATE INDEX 执行期间查询 pg_stat_progress_create_index:

SELECT
    phase,
    round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%"
FROM pg_stat_progress_create_index;
  • HNSW 阶段:initializing →\rightarrow loading tuples
  • IVFFlat 阶段:initializing →\rightarrow performing k-means →\rightarrow assigning tuples →\rightarrow loading tuples

HNSW 索引的 VACUUM 维护

在大批量删除数据后,直接对 HNSW 索引执行 VACUUM 可能会因为修复图边连接而耗时较长。此时可先并发重建索引,再执行 VACUUM:

REINDEX INDEX CONCURRENTLY items_embedding_idx;
VACUUM items;

4 - 向量量化与稀疏向量

pgvector 中的半精度向量(halfvec)、二值量化(bit)、稀疏向量(sparsevec)与套娃(Matryoshka)子向量索引。

pgvector 支持四种向量数据类型,方便您在内存占用、维度上限与检索召回率之间灵活权衡:

数据类型 元素精度 索引最大维度上限 存储空间占用
vector(n) 32 位浮点(float32) 2,000 维 4n+84n + 8 字节
halfvec(n) 16 位半精度浮点(float16) 4,000 维 2n+82n + 8 字节
bit(n) 1 位二值比特(0 / 1) 64,000 维 ⌈n/8⌉+8\lceil n / 8 \rceil + 8 字节
sparsevec(n) 非零 下标:float32 键值对 最多 1,000 个非零元素(总维度可达 100 万) 8×nnz+168 \times \text{nnz} + 16 字节
vchord 中的 RaBitQ 量化

除了 pgvector 内置的量化类型外,vchord 还提供 rabitq8(8-bit)与 rabitq4(4-bit)专用量化向量类型,并在 vchordrq 索引中支持高达 60,000 维的超长向量。详见 vchord 量化类型。


半精度浮点向量(halfvec)

使用 halfvec 类型(自 pgvector 0.7.0 起引入)存储 16 位半精度浮点向量,相比 vector 可将表与索引体积直接缩减 50%:

CREATE TABLE items (
    id bigserial PRIMARY KEY,
    embedding halfvec(3)
);

CREATE INDEX ON items USING hnsw (embedding halfvec_l2_ops);

半精度表达式索引(标量量化)

如果您希望在表中保留完整的 32 位 vector 精度(或者需要为 2,001 至 4,000 维的向量建索引,例如 3,072 维的 OpenAI text-embedding-3-large),可以通过表达式索引将 vector 转换为 halfvec:

CREATE TABLE items (
    id bigserial PRIMARY KEY,
    embedding vector(3072)
);

CREATE INDEX ON items USING hnsw ((embedding::halfvec(3072)) halfvec_l2_ops);

-- 查询时使用与索引一致的转换表达式
SELECT * FROM items
ORDER BY embedding::halfvec(3072) <-> '[1,2,3,...]'
LIMIT 5;

二值向量(bit)与二值量化

结合 PostgreSQL 内置的 bit(n) 类型与 pgvector 的汉明距离(<~>)及杰卡德距离(<%>)操作符,可存储并索引高达 64,000 位的二值向量:

CREATE TABLE items (
    id bigserial PRIMARY KEY,
    embedding bit(3)
);

INSERT INTO items (embedding) VALUES ('000'), ('111');

-- 按汉明距离检索最近邻
SELECT * FROM items ORDER BY embedding <~> '101' LIMIT 5;

-- 创建 HNSW 索引
CREATE INDEX ON items USING hnsw (embedding bit_hamming_ops);

二值量化索引 + 全精度重排序(Re-Ranking)

使用 binary_quantize(vector) 函数在表达式索引中将每个维度压缩为 1 比特(大于 0 为 1,否则为 0),并在子查询召回候选集后使用原始 vector 列执行精确重排:

CREATE INDEX ON items USING hnsw ((binary_quantize(embedding)::bit(3)) bit_hamming_ops);

SELECT * FROM (
    SELECT * FROM items
    ORDER BY binary_quantize(embedding)::bit(3) <~> binary_quantize('[1,-2,3]')
    LIMIT 20
) AS candidates
ORDER BY embedding <=> '[1,-2,3]'
LIMIT 5;

稀疏向量(sparsevec)

使用 sparsevec(自 pgvector 0.7.0 起引入)存储绝大部分维度为零的稀疏向量(例如 SPLADE、BGE-M3 稀疏输出,或由 pg_bestmatch 生成的 BM25 词频权重向量)。

稀疏向量字面量格式

语法格式为 '{下标1:值1,下标2:值2}/总维度',其中下标从 1 开始计数:

CREATE TABLE items (
    id bigserial PRIMARY KEY,
    embedding sparsevec(5)
);

INSERT INTO items (embedding) VALUES ('{1:1,3:2,5:3}/5'), ('{1:4,3:5,5:6}/5');

-- 检索最近邻
SELECT * FROM items ORDER BY embedding <-> '{1:3,3:1,5:2}/5' LIMIT 5;

-- 创建 HNSW 索引(支持最多 1,000 个非零元素)
CREATE INDEX ON items USING hnsw (embedding sparsevec_l2_ops);

套娃(Matryoshka)子向量索引(subvector)

对于支持套娃表示学习(Matryoshka Representation Learning, MRL)的嵌入模型,可以使用 subvector(vector, start, count) 仅对前 MM 个维度建立轻量级索引,再利用完整向量执行精确重排:

CREATE INDEX ON items USING hnsw ((subvector(embedding, 1, 512)::vector(512)) vector_cosine_ops);

SELECT * FROM (
    SELECT * FROM items
    ORDER BY subvector(embedding, 1, 512)::vector(512) <=> subvector('[1,2,3,...]'::vector, 1, 512)
    LIMIT 20
) AS candidates
ORDER BY embedding <=> '[1,2,3,...]'
LIMIT 5;

5 - 参考手册、调优与 FAQ

pgvector 的完整 SQL 函数参考、GUC 配置参数、性能调优、监控方法与常见问题解答。

SQL 函数与操作符速查表

向量函数

函数 返回类型 说明
l2_distance(a, b) float8 计算 a 与 b 之间的欧氏(L2)距离(支持 vector, halfvec, sparsevec)
inner_product(a, b) float8 计算内积 ∑aibi\sum a_i b_i(支持 vector, halfvec, sparsevec)
cosine_distance(a, b) float8 计算余弦距离 1−a⋅b∥a∥∥b∥1 - \frac{a \cdot b}{\|a\|\|b\|}(支持 vector, halfvec, sparsevec)
l1_distance(a, b) float8 计算曼哈顿(L1)距离 (\sum
hamming_distance(a, b) float8 计算两个 bit 位向量之间的汉明距离
jaccard_distance(a, b) float8 计算两个 bit 位向量之间的杰卡德距离
vector_dims(a) integer 返回向量的维度数(支持 vector, halfvec, sparsevec)
vector_norm(a) float8 返回向量的欧氏范数 ∥a∥2\|a\|_2(支持 vector, halfvec, sparsevec)
l2_normalize(a) 与输入相同 将向量归一化为单位 L2 长度(支持 vector, halfvec, sparsevec)
binary_quantize(a) bit 将 vector 或 halfvec 的每个元素二值化为 1(>0> 0)或 0(≤0\le 0)
subvector(a, start, count) 与输入相同 从 1 起始下标 start 处截取长度为 count 的子向量(支持 vector, halfvec)

逐元素算术操作符

  • a + b:逐元素加法(vector, halfvec)
  • a - b:逐元素减法(vector, halfvec)
  • a * b:逐元素乘法(vector, halfvec)
  • a || b:向量拼接(vector, halfvec)

GUC 配置参数

参数名称 类型 / 允许取值 默认值 说明
hnsw.ef_search integer(1–1000) 40 HNSW 查询时的动态候选列表大小
hnsw.iterative_scan off, relaxed_order, strict_order off 当 WHERE 条件过滤导致结果少于 LIMIT 时,自动继续扫描 HNSW 索引
hnsw.max_scan_tuples integer 20000 HNSW 迭代扫描期间最多访问的元组数量
hnsw.scan_mem_multiplier real 1 HNSW 迭代扫描维护访问状态可使用的 work_mem 倍数
ivfflat.probes integer(1–lists) 1 IVFFlat 查询时探测的倒排列表数量
ivfflat.iterative_scan off, relaxed_order off 当 WHERE 条件过滤导致结果少于 LIMIT 时,自动探测更多 IVFFlat 分桶
ivfflat.max_probes integer 32768 IVFFlat 迭代扫描期间最多探测的倒排列表数量

性能调优与监控

1. 查看索引体积

SELECT pg_size_pretty(pg_relation_size('items_embedding_idx'));

2. 检查查询执行计划

使用 EXPLAIN ANALYZE 确认查询是否命中向量索引并查看缓冲区命中与耗时:

EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

3. 使用 pg_stat_statements 监控慢查询

SELECT
    calls,
    round((total_plan_time + total_exec_time) / calls) AS avg_time_ms,
    round((total_plan_time + total_exec_time) / 60000) AS total_time_min,
    query
FROM pg_stat_statements
ORDER BY total_plan_time + total_exec_time DESC
LIMIT 20;

4. 评估近似检索召回率(Recall)

在事务内临时关闭索引扫描,获取精确最近邻基准(Ground Truth)并与近似结果对比:

BEGIN;
SET LOCAL enable_indexscan = off;
-- 在此执行精确查询以获取基准 ID 列表
COMMIT;

常见问题解答(FAQ)

为什么我的查询没有走向量索引?

  1. 缺少 ORDER BY ... LIMIT:向量索引扫描要求查询同时包含 ORDER BY <距离操作符> 与 LIMIT 子句。
  2. 操作符与索引操作符类不匹配:查询操作符必须与创建索引时的操作符类一致(<-> 对应 vector_l2_ops,<#> 对应 vector_ip_ops,<=> 对应 vector_cosine_ops)。
  3. 小表成本估算:当表行数较少时,PostgreSQL 优化器认为全表顺序扫描比走索引更快。在测试环境中可通过 SET LOCAL enable_seqscan = off; 强制走索引验证。

如何对超过 2,000 维的向量建立索引?

受限于 PostgreSQL 8 KB 页面元组大小,内置的 HNSW 与 IVFFlat 索引对 vector 类型的维度上限为 2,000 维。您有三种解决方案:

  1. 安装 vchord:vchord 的 vchordrq 索引直接在 vector 与 halfvec 列上支持高达 60,000 维的超长向量。
  2. 使用 halfvec 半精度表达式索引:通过 (embedding::halfvec(3072)) halfvec_l2_ops 最高支持 4,000 维。
  3. 使用二值量化表达式索引:通过 (binary_quantize(embedding)::bit(N)) bit_hamming_ops 最高支持 64,000 维。

可以在同一列中存储不同维度的向量吗?

可以,定义列时不指定维度即可(embedding vector)。如果需要建索引,可以针对特定维度的行创建部分表达式索引:

CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector);
CREATE INDEX ON items USING hnsw ((embedding::vector(3)) vector_l2_ops) WHERE (vector_dims(embedding) = 3);

向量中可以包含 NULL、NaN 或 Infinity 吗?

向量内部的元素不能为 NULL、NaN 或 Infinity。整列的值可以为 NULL;请注意 IVFFlat 不会对 NULL 值建索引。