vector

向量数据类型和 ivfflat / hnsw 访问方法

概览

扩展包名版本分类许可证语言
pgvector0.8.2RAGPostgreSQLC
ID扩展名BinLibLoadCreateTrustReloc模式
1800vector-
相关扩展pg_bestmatch pg_summarize pg_tiktoken pg4ml pgml pg_similarity smlar pg_search
下游依赖documentdb vchord vectorize vectorscale

版本

类型仓库版本PG 大版本包名依赖
EXTPGDG0.8.21817161514pgvector-
RPMPGDG0.8.21817161514pgvector_$v-
DEBPGDG0.8.21817161514postgresql-$v-pgvector-
OS / PGPG18PG17PG16PG15PG14
el8.x86_64
el8.aarch64
el9.x86_64
el9.aarch64
el10.x86_64
el10.aarch64
d12.x86_64
d12.aarch64
d13.x86_64
d13.aarch64
u22.x86_64
u22.aarch64
u24.x86_64
u24.aarch64

构建

您可以使用 pig build 命令构建 pgvector 扩展的 RPM 包:

pig build pkg pgvector         # 构建 RPM 包

安装

您可以直接安装 pgvector 扩展包的预置二进制包,首先确保 PGDG 仓库已经添加并启用:

pig repo add pgdg -u          # 添加 PGDG 仓库并更新缓存

使用 pig 或者是 apt/yum/dnf 安装扩展:

pig install pgvector;          # 当前活跃 PG 版本安装
pig ext install -y pgvector -v 18  # PG 18
pig ext install -y pgvector -v 17  # PG 17
pig ext install -y pgvector -v 16  # PG 16
pig ext install -y pgvector -v 15  # PG 15
pig ext install -y pgvector -v 14  # PG 14
dnf install -y pgvector_18       # PG 18
dnf install -y pgvector_17       # PG 17
dnf install -y pgvector_16       # PG 16
dnf install -y pgvector_15       # PG 15
dnf install -y pgvector_14       # PG 14
apt install -y postgresql-18-pgvector   # PG 18
apt install -y postgresql-17-pgvector   # PG 17
apt install -y postgresql-16-pgvector   # PG 16
apt install -y postgresql-15-pgvector   # PG 15
apt install -y postgresql-14-pgvector   # PG 14

创建扩展

CREATE EXTENSION vector;

用法

适用于 PostgreSQL 的开源向量相似性搜索扩展。将向量与其他数据存储在一起,支持:

  • 精确与近似最近邻搜索
  • 单精度、半精度、二进制和稀疏向量
  • L2 距离、内积、余弦距离、L1 距离、汉明距离和 Jaccard 距离
  • 任何具有 PostgreSQL 客户端的编程语言

此外还具备 ACID 合规性、时间点恢复(PITR)、JOIN 以及 PostgreSQL 的所有其他优秀特性

快速上手

启用扩展(在每个需要使用该扩展的数据库中执行一次)

CREATE EXTENSION vector;

创建一个 3 维向量列

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

插入向量

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

按 L2 距离获取最近邻

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

还支持内积(<#>)、余弦距离(<=>)和 L1 距离(<+>

注意:<#> 返回的是负内积,因为 PostgreSQL 的索引扫描仅支持 ASC 排序的操作符


存储

创建一个带有向量列的新表

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

或者向已有表添加向量列

ALTER TABLE items ADD COLUMN embedding vector(3);

还支持半精度二进制稀疏向量

插入向量

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

或使用 COPY 批量导入向量(示例

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

更新插入(Upsert)向量

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

更新向量

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

删除向量

DELETE FROM items WHERE id = 1;

查询

获取某个向量的最近邻

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

支持的距离函数:

  • <-> - L2 距离
  • <#> - (负)内积
  • <=> - 余弦距离
  • <+> - L1 距离
  • <~> - 汉明距离(二进制向量)
  • <%> - Jaccard 距离(二进制向量)

获取某行的最近邻

SELECT * FROM items WHERE id != 1 ORDER BY embedding <-> (SELECT embedding FROM items WHERE id = 1) LIMIT 5;

获取指定距离范围内的行

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

注意:配合 ORDER BYLIMIT 使用才能利用索引

距离计算

获取距离值

SELECT embedding <-> '[3,1,2]' AS distance FROM items;

对于内积,需要乘以 -1(因为 <#> 返回的是负内积)

SELECT (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;

对于余弦相似度,使用 1 减去余弦距离

SELECT 1 - (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;

聚合

计算向量平均值

SELECT AVG(embedding) FROM items;

按分组计算向量平均值

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

索引

默认情况下,pgvector 执行精确最近邻搜索,提供完美的召回率。

可以添加索引来使用近似最近邻搜索,以牺牲部分召回率换取速度提升。与普通索引不同,添加近似索引后查询结果可能会有所变化。

支持的索引类型:

HNSW

HNSW 索引会创建一个多层图结构。相比 IVFFlat,它具有更好的查询性能(在速度与召回率的权衡上),但构建时间更长且占用更多内存。此外,由于没有像 IVFFlat 那样的训练步骤,HNSW 索引可以在表中没有数据时就创建。

为所需的每种距离函数添加索引。

L2 距离

CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);

注意:halfvec 类型使用 halfvec_l2_opssparsevec 类型使用 sparsevec_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);

Jaccard 距离

CREATE INDEX ON items USING hnsw (embedding bit_jaccard_ops);

支持的类型:

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

索引选项

指定 HNSW 参数

  • m - 每层的最大连接数(默认 16)
  • ef_construction - 构建图时动态候选列表的大小(默认 64)
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WITH (m = 16, ef_construction = 64);

ef_construction 值越大,召回率越高,但索引构建时间和插入耗时也会相应增加。

查询选项

指定搜索时动态候选列表的大小(默认 40)

SET hnsw.ef_search = 100;

该值越大,召回率越高,但查询速度会相应下降。

在事务中使用 SET LOCAL 可以仅对单次查询生效

BEGIN;
SET LOCAL hnsw.ef_search = 100;
SELECT ...
COMMIT;

索引构建时间

当图结构能完全放入 maintenance_work_mem 时,索引构建速度会显著提升

SET maintenance_work_mem = '8GB';

当图结构无法再放入内存时,会显示如下提示

NOTICE:  hnsw graph no longer fits into maintenance_work_mem after 100000 tuples
DETAIL:  Building will take significantly more time.
HINT:  Increase maintenance_work_mem to speed up builds.

注意:不要将 maintenance_work_mem 设置得过高以至于耗尽服务器内存

与其他索引类型一样,在加载完初始数据之后再创建索引会更快

还可以通过增加并行工作进程数来加速索引创建(默认 2 个)

SET max_parallel_maintenance_workers = 7; -- 加上 leader 进程

如果工作进程数较多,可能需要同时增大 max_parallel_workers(默认 8)

索引选项对构建时间也有显著影响(除非召回率偏低,否则使用默认值即可)

索引构建进度

查看索引构建进度

SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;

HNSW 的构建阶段:

  1. initializing
  2. loading tuples

IVFFlat

IVFFlat 索引将向量划分到多个列表中,然后搜索与查询向量最接近的那些列表的子集。相比 HNSW,它构建速度更快且占用内存更少,但查询性能较低(在速度与召回率的权衡上)。

实现良好召回率的三个关键:

  1. 在表中已有一定数据之后再创建索引
  2. 选择合适的列表数量——对于不超过 100 万行的数据,可从 rows / 1000 开始;超过 100 万行的数据则使用 sqrt(rows)
  3. 查询时指定合适的探针数(值越高召回率越好,值越低速度越快)——可从 sqrt(lists) 开始

为所需的每种距离函数添加索引。

L2 距离

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

注意:halfvec 类型使用 halfvec_l2_ops(其他距离函数同理)

内积

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);

支持的类型:

  • vector - 最多 2,000 维
  • halfvec - 最多 4,000 维
  • bit - 最多 64,000 维

查询选项

指定探针数(默认 1)

SET ivfflat.probes = 10;

该值越大,召回率越高,但速度会相应下降。可以将其设置为列表总数以实现精确最近邻搜索(此时查询规划器将不会使用索引)

在事务中使用 SET LOCAL 可以仅对单次查询生效

BEGIN;
SET LOCAL ivfflat.probes = 10;
SELECT ...
COMMIT;

索引构建时间

对于大表,可以通过增加并行工作进程数来加速索引创建(默认 2 个)

SET max_parallel_maintenance_workers = 7; -- 加上 leader 进程

如果工作进程数较多,可能还需要同时增大 max_parallel_workers(默认 8)

索引构建进度

查看索引构建进度

SELECT phase, round(100.0 * tuples_done / nullif(tuples_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;

IVFFlat 的构建阶段:

  1. initializing
  2. performing k-means
  3. assigning tuples
  4. loading tuples

注意:% 仅在 loading tuples 阶段显示

过滤

有多种方式可以对带有 WHERE 子句的最近邻查询建立索引。

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

首先可以在过滤列上创建索引。在很多场景下,这可以提供快速的精确最近邻搜索。PostgreSQL 为此提供了多种索引类型:B-tree(默认)、hash、GiST、SP-GiST、GIN 和 BRIN。

CREATE INDEX ON items (category_id);

对于多列过滤,可以考虑使用多列索引

CREATE INDEX ON items (location_id, category_id);

精确索引适用于匹配行数占比较低的条件。否则,近似索引可能效果更好。

CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);

使用近似索引时,过滤是在索引扫描之后应用的。如果某个条件匹配 10% 的行,在 HNSW 默认 hnsw.ef_search 为 40 的情况下,平均只有 4 行会匹配。要获取更多行,请增大 hnsw.ef_search

SET hnsw.ef_search = 200;

从 0.8.0 版本开始,可以启用迭代索引扫描,在需要时自动扫描索引的更多部分。

SET hnsw.iterative_scan = strict_order;

如果只按少数几个不同的值过滤,可以考虑使用部分索引

CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WHERE (category_id = 123);

如果按大量不同的值过滤,可以考虑使用分区表

CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id);

迭代索引扫描

使用近似索引时,带有过滤条件的查询可能返回较少的结果,因为过滤是在索引扫描之后应用的。从 0.8.0 版本开始,可以启用迭代索引扫描,它会自动扫描索引的更多部分,直到找到足够的结果(或达到 hnsw.max_scan_tuplesivfflat.max_probes 的限制)。

迭代扫描可以使用严格排序或宽松排序。

严格排序确保结果按距离精确排序

SET hnsw.iterative_scan = strict_order;

宽松排序允许结果在距离排序上略有偏差,但能提供更好的召回率

SET hnsw.iterative_scan = relaxed_order;
# or
SET ivfflat.iterative_scan = relaxed_order;

使用宽松排序时,可以通过物化 CTE 来获得严格排序

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

注意:PostgreSQL 17+ 需要 + 0

对于按距离过滤的查询,请使用物化 CTE 并将距离过滤条件放在 CTE 外部以获得最佳性能(这是由于 PostgreSQL 执行器的当前行为所致)

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

注意:其他过滤条件请放在 CTE 内部

迭代扫描选项

由于扫描近似索引的大部分内容开销很大,因此提供了控制扫描何时终止的选项。

HNSW

指定最大访问元组数(默认 20,000)

SET hnsw.max_scan_tuples = 20000;

注意:该值为近似值,不影响初始扫描

指定最大可用内存量,以 work_mem 的倍数表示(默认 1)

SET hnsw.scan_mem_multiplier = 2;

注意:如果增大 hnsw.max_scan_tuples 未能改善召回率,可尝试增大此值

IVFFlat

指定最大探针数

SET ivfflat.max_probes = 100;

注意:如果该值低于 ivfflat.probes,则使用 ivfflat.probes 的值


向量类型

半精度向量

使用 halfvec 类型存储半精度向量

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

半精度索引

以半精度对向量建立索引,可以获得更小的索引体积

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

获取最近邻

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

二进制向量

使用 bit 类型存储二进制向量(示例

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;

还支持 Jaccard 距离(<%>

二进制量化

使用表达式索引进行二进制量化

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

按汉明距离获取最近邻

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

使用原始向量重新排序以提高召回率

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

稀疏向量

使用 sparsevec 类型存储稀疏向量

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');

格式为 {索引1:值1,索引2:值2}/维度数,索引从 1 开始,与 SQL 数组一致

按 L2 距离获取最近邻

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

混合搜索

结合 PostgreSQL 的全文搜索实现混合搜索。

SELECT id, content FROM items, plainto_tsquery('hello search') query
    WHERE textsearch @@ query ORDER BY ts_rank_cd(textsearch, query) DESC LIMIT 5;

可以使用倒数排名融合(RRF)交叉编码器来合并结果。

子向量索引

使用表达式索引对子向量建立索引

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

按余弦距离获取最近邻

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

使用完整向量重新排序以提高召回率

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

性能

调优

使用 PgTune 等工具来设置 PostgreSQL 服务器参数的初始值。例如,shared_buffers 通常应设置为服务器内存的 25%。可以通过以下命令查找配置文件路径:

SHOW config_file;

查看各项参数设置:

SHOW shared_buffers;

修改后需要重启 PostgreSQL 才能生效。

数据加载

使用 COPY 批量加载数据(示例)。

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

为获得最佳性能,建议在加载完初始数据之后再创建索引。

索引

关于索引构建时间,参见 HNSWIVFFlat

在生产环境中,请使用并发方式创建索引以避免阻塞写操作。

CREATE INDEX CONCURRENTLY ...

查询

使用 EXPLAIN (ANALYZE, BUFFERS) 调试查询性能。

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

精确搜索

对于没有索引的查询,可以增大 max_parallel_workers_per_gather 来加速。

SET max_parallel_workers_per_gather = 4;

如果向量已归一化为单位长度(如 OpenAI embeddings),使用内积可获得最佳性能。

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

近似搜索

对于使用 IVFFlat 索引的查询,可以增加倒排列表数量来加速(会牺牲部分召回率)。

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

清理(VACUUM)

HNSW 索引的 VACUUM 操作可能耗时较长。可以先重建索引来加速。

REINDEX INDEX CONCURRENTLY index_name;
VACUUM table_name;

监控

使用 pg_stat_statements 监控性能(需确保已将其添加到 shared_preload_libraries)。

CREATE EXTENSION pg_stat_statements;

查询最耗时的 SQL:

SELECT query, 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
    FROM pg_stat_statements ORDER BY total_plan_time + total_exec_time DESC LIMIT 20;

通过对比近似搜索与精确搜索的结果来监控召回率。

BEGIN;
SET LOCAL enable_indexscan = off; -- 使用精确搜索
SELECT ...
COMMIT;

扩展

pgvector 的扩展方式与 PostgreSQL 相同。

纵向扩展:增加单个实例的内存、CPU 和存储容量。使用现有工具进行参数调优性能监控

横向扩展:使用只读副本,或使用 Citus 等方案进行分片(示例)。


语言支持

可以从任何具有 PostgreSQL 客户端的编程语言中使用 pgvector。甚至可以在一种语言中生成和存储向量,在另一种语言中进行查询。

语言库 / 示例
Adapgvector-ada
Algolpgvector-algol
Cpgvector-c
C++pgvector-cpp
C#, F#, Visual Basicpgvector-dotnet
COBOLpgvector-cobol
Crystalpgvector-crystal
Dpgvector-d
Dartpgvector-dart
Elixirpgvector-elixir
Erlangpgvector-erlang
Fortranpgvector-fortran
Gleampgvector-gleam
Gopgvector-go
Haskellpgvector-haskell
Java, Kotlin, Groovy, Scalapgvector-java
JavaScript, TypeScriptpgvector-node
JuliaPgvector.jl
Lisppgvector-lisp
Luapgvector-lua
Nimpgvector-nim
OCamlpgvector-ocaml
Pascalpgvector-pascal
Perlpgvector-perl
PHPpgvector-php
Prologpgvector-prolog
Pythonpgvector-python
Rpgvector-r
Racketpgvector-racket
Rakupgvector-raku
Rubypgvector-ruby, Neighbor
Rustpgvector-rust
Swiftpgvector-swift
Tclpgvector-tcl
Zigpgvector-zig

常见问题

单张表最多能存储多少向量?

PostgreSQL 中非分区表默认上限为 32 TB。分区表可以有数千个该大小的分区。

是否支持复制?

是的,pgvector 使用预写式日志(WAL),支持流复制和时间点恢复(PITR)。

如果我想对超过 2,000 维的向量建立索引怎么办?

可以使用半精度向量半精度索引来索引最多 4,000 维的向量,或使用二进制量化来索引最多 64,000 维的向量。其他方案包括子向量索引(需要模型支持)或降维

能否在同一列中存储不同维度的向量?

可以使用 vector 作为类型(而非 vector(n))。

CREATE TABLE embeddings (model_id bigint, item_id bigint, embedding vector, PRIMARY KEY (model_id, item_id));

但只能对维度相同的行创建索引(使用表达式索引部分索引):

CREATE INDEX ON embeddings USING hnsw ((embedding::vector(3)) vector_l2_ops) WHERE (model_id = 123);

查询方式:

SELECT * FROM embeddings WHERE model_id = 123 ORDER BY embedding::vector(3) <-> '[3,1,2]' LIMIT 5;

能否以更高精度存储向量?

可以使用 double precision[]numeric[] 类型来存储更高精度的向量。

CREATE TABLE items (id bigserial PRIMARY KEY, embedding double precision[]);

-- PostgreSQL 数组使用 {} 而非 []
INSERT INTO items (embedding) VALUES ('{1,2,3}'), ('{4,5,6}');

可以选择添加检查约束,确保数据可以转换为 vector 类型并具有预期的维度。

ALTER TABLE items ADD CHECK (vector_dims(embedding::vector) = 3);

使用表达式索引建立索引(以较低精度):

CREATE INDEX ON items USING hnsw ((embedding::vector(3)) vector_l2_ops);

查询方式:

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

索引是否需要完全放入内存?

不需要,但与其他索引类型一样,索引能放入内存时性能通常更好。可以通过以下命令查看索引大小:

SELECT pg_size_pretty(pg_relation_size('index_name'));

故障排查

为什么查询没有使用索引?

查询需要同时包含 ORDER BYLIMIT,且 ORDER BY 必须直接使用距离操作符的结果(不能是表达式),并且必须为升序排列。

-- 使用索引
ORDER BY embedding <=> '[3,1,2]' LIMIT 5;

-- 不使用索引
ORDER BY 1 - (embedding <=> '[3,1,2]') DESC LIMIT 5;

可以通过以下方式引导查询规划器使用索引:

BEGIN;
SET LOCAL enable_seqscan = off;
SELECT ...
COMMIT;

另外,如果表很小,全表扫描可能反而更快。

为什么查询没有使用并行表扫描?

查询规划器在成本估算中不考虑行外存储(TOAST),这可能导致串行扫描看起来成本更低。可以通过以下方式降低并行扫描的成本估算:

BEGIN;
SET LOCAL min_parallel_table_scan_size = 1;
SET LOCAL parallel_setup_cost = 1;
SELECT ...
COMMIT;

或者选择以内联方式存储向量:

ALTER TABLE items ALTER COLUMN embedding SET STORAGE PLAIN;

为什么添加 HNSW 索引后查询结果变少了?

结果数量受动态候选列表大小(hnsw.ef_search)的限制,默认值为 40。由于死元组或查询中的过滤条件,结果可能会更少。启用迭代索引扫描有助于解决此问题。

另外请注意,NULL 向量不会被索引(余弦距离的零向量也不会被索引)。

为什么添加 IVFFlat 索引后查询结果变少了?

很可能是在数据量相对于列表数量不足时就创建了索引。请先删除索引,等表中有更多数据后再重新创建。

DROP INDEX index_name;

结果数量也可能受探针数(ivfflat.probes)的限制。启用迭代索引扫描可以解决此问题。

另外请注意,NULL 向量不会被索引(余弦距离的零向量也不会被索引)。


参考

Vector 类型

每个向量占用 4 * 维度数 + 8 字节的存储空间。每个元素为单精度浮点数(类似于 PostgreSQL 中的 real 类型),所有元素必须为有限值(不允许 NaNInfinity-Infinity)。向量最多支持 16,000 维。

Vector 操作符

操作符描述引入版本
+逐元素加法
-逐元素减法
*逐元素乘法0.5.0
||拼接0.7.0
<->欧氏距离
<#>负内积
<=>余弦距离
<+>曼哈顿距离0.7.0

Vector 函数

函数描述引入版本
binary_quantize(vector) → bit二进制量化0.7.0
cosine_distance(vector, vector) → double precision余弦距离
inner_product(vector, vector) → double precision内积
l1_distance(vector, vector) → double precision曼哈顿距离0.5.0
l2_distance(vector, vector) → double precision欧氏距离
l2_normalize(vector) → vector欧氏范数归一化0.7.0
subvector(vector, integer, integer) → vector子向量0.7.0
vector_dims(vector) → integer维度数
vector_norm(vector) → double precision欧氏范数

Vector 聚合函数

函数描述引入版本
avg(vector) → vector平均值
sum(vector) → vector求和0.5.0

Halfvec 类型

每个半精度向量占用 2 * 维度数 + 8 字节的存储空间。每个元素为半精度浮点数,所有元素必须为有限值(不允许 NaNInfinity-Infinity)。半精度向量最多支持 16,000 维。

Halfvec 操作符

操作符描述引入版本
+逐元素加法0.7.0
-逐元素减法0.7.0
*逐元素乘法0.7.0
||拼接0.7.0
<->欧氏距离0.7.0
<#>负内积0.7.0
<=>余弦距离0.7.0
<+>曼哈顿距离0.7.0

Halfvec 函数

函数描述引入版本
binary_quantize(halfvec) → bit二进制量化0.7.0
cosine_distance(halfvec, halfvec) → double precision余弦距离0.7.0
inner_product(halfvec, halfvec) → double precision内积0.7.0
l1_distance(halfvec, halfvec) → double precision曼哈顿距离0.7.0
l2_distance(halfvec, halfvec) → double precision欧氏距离0.7.0
l2_norm(halfvec) → double precision欧氏范数0.7.0
l2_normalize(halfvec) → halfvec欧氏范数归一化0.7.0
subvector(halfvec, integer, integer) → halfvec子向量0.7.0
vector_dims(halfvec) → integer维度数0.7.0

Halfvec 聚合函数

函数描述引入版本
avg(halfvec) → halfvec平均值0.7.0
sum(halfvec) → halfvec求和0.7.0

Bit 类型

每个位向量占用 维度数 / 8 + 8 字节的存储空间。更多信息参见 PostgreSQL 文档

Bit 操作符

操作符描述引入版本
<~>汉明距离0.7.0
<%>Jaccard 距离0.7.0

Bit 函数

函数描述引入版本
hamming_distance(bit, bit) → double precision汉明距离0.7.0
jaccard_distance(bit, bit) → double precisionJaccard 距离0.7.0

Sparsevec 类型

每个稀疏向量占用 8 * 非零元素数 + 16 字节的存储空间。每个元素为单精度浮点数,所有元素必须为有限值(不允许 NaNInfinity-Infinity)。稀疏向量最多支持 16,000 个非零元素。

Sparsevec 操作符

操作符描述引入版本
<->欧氏距离0.7.0
<#>负内积0.7.0
<=>余弦距离0.7.0
<+>曼哈顿距离0.7.0

Sparsevec 函数

函数描述引入版本
cosine_distance(sparsevec, sparsevec) → double precision余弦距离0.7.0
inner_product(sparsevec, sparsevec) → double precision内积0.7.0
l1_distance(sparsevec, sparsevec) → double precision曼哈顿距离0.7.0
l2_distance(sparsevec, sparsevec) → double precision欧氏距离0.7.0
l2_norm(sparsevec) → double precision欧氏范数0.7.0
l2_normalize(sparsevec) → sparsevec欧氏范数归一化0.7.0

安装

Linux 与 Mac

编译安装扩展(支持 PostgreSQL 13+)

cd /tmp
git clone --branch v0.8.2 https://github.com/pgvector/pgvector.git
cd pgvector
make
make install # 可能需要 sudo

如果遇到问题,请参阅安装说明

也可以通过 DockerHomebrewPGXNAPTYumpkgAPKconda-forge 安装,Postgres.app 和许多托管服务商已预装此扩展。此外还有 GitHub Actions 的使用说明。

Windows

确保已安装 Visual Studio 中的 C++ 支持,并以管理员身份运行 x64 Native Tools Command Prompt for VS [版本]。然后使用 nmake 编译:

set "PGROOT=C:\Program Files\PostgreSQL\18"
cd %TEMP%
git clone --branch v0.8.2 https://github.com/pgvector/pgvector.git
cd pgvector
nmake /F Makefile.win
nmake /F Makefile.win install

如果遇到问题,请参阅安装说明

也可以通过 Dockerconda-forge 安装。

安装说明 - Linux 与 Mac

PostgreSQL 路径

如果机器上有多个 PostgreSQL 安装,请通过以下方式指定 pg_config 的路径:

export PG_CONFIG=/Library/PostgreSQL/18/bin/pg_config

然后重新执行安装步骤(如需要,在 make 前先执行 make clean)。如果 make install 需要 sudo,请使用:

sudo --preserve-env=PG_CONFIG make install

Mac 上常见的路径包括:

  • EDB 安装器 - /Library/PostgreSQL/18/bin/pg_config
  • Homebrew (arm64) - /opt/homebrew/opt/postgresql@18/bin/pg_config
  • Homebrew (x86-64) - /usr/local/opt/postgresql@18/bin/pg_config

注意:请将 18 替换为实际的 PostgreSQL 服务器版本

缺少头文件

如果编译报错 fatal error: postgres.h: No such file or directory,请确保服务器上已安装 PostgreSQL 开发文件。

对于 Ubuntu 和 Debian,使用:

sudo apt install postgresql-server-dev-18

注意:请将 18 替换为实际的 PostgreSQL 服务器版本

缺少 SDK

如果在 Mac 上编译失败且输出包含 warning: no such sysroot directory,说明 PostgreSQL 安装指向了一个已不存在的路径。

pg_config --cppflags

重新安装 PostgreSQL 即可修复此问题。

可移植性

默认情况下,pgvector 在某些平台上会使用 -march=native 编译以获得最佳性能。但如果要在其他机器上运行编译好的扩展,这可能导致 Illegal instruction 错误。

要以可移植方式编译,请使用:

make OPTFLAGS=""

安装说明 - Windows

缺少头文件

如果编译报错 Cannot open include file: 'postgres.h': No such file or directory,请确保 PGROOT 设置正确。

架构不匹配

如果编译报错 error C2196: case value '4' already used,请确保使用的是 x64 Native Tools Command Prompt。然后执行 nmake /F Makefile.win clean 并重新执行安装步骤。

缺少符号

如果在 PostgreSQL 17.0-17.2 版本上链接失败并提示 unresolved external symbol float_to_shortest_decimal_bufn,请升级到 PostgreSQL 17.3+。

权限问题

如果安装失败并提示 Access is denied,请以管理员身份重新执行安装步骤。

其他安装方式

Docker

获取 Docker 镜像

docker pull pgvector/pgvector:pg18-trixie

该镜像在 PostgreSQL 镜像的基础上添加了 pgvector(请将 18 替换为实际的 PostgreSQL 服务器版本,使用方式相同)。

也可以手动构建镜像:

git clone --branch v0.8.2 https://github.com/pgvector/pgvector.git
cd pgvector
docker build --pull --build-arg PG_MAJOR=18 -t myuser/pgvector .

如果增大了 maintenance_work_mem,请确保 --shm-size 至少为该值,以避免并行 HNSW 索引构建时出错。

docker run --shm-size=1g ...

Homebrew

对于 Homebrew 安装的 PostgreSQL,可以使用:

brew install pgvector

注意:仅适用于 postgresql@18postgresql@17

PGXN

PostgreSQL 扩展网络安装:

pgxn install vector

APT

Debian 和 Ubuntu 软件包可从 PostgreSQL APT 仓库获取。按照配置说明操作后执行:

sudo apt install postgresql-18-pgvector

注意:请将 18 替换为实际的 PostgreSQL 服务器版本

Yum

RPM 软件包可从 PostgreSQL Yum 仓库获取。按照对应发行版的配置说明操作后执行:

sudo yum install pgvector_18
# 或
sudo dnf install pgvector_18

注意:请将 18 替换为实际的 PostgreSQL 服务器版本

pkg

安装 FreeBSD 软件包:

pkg install postgresql17-pgvector

或通过 port 安装:

cd /usr/ports/databases/pgvector
make install

APK

安装 Alpine 软件包:

apk add postgresql-pgvector

conda-forge

对于 Conda 安装的 PostgreSQL,从 conda-forge 安装:

conda install -c conda-forge pgvector

该方式由 @mmcauliffe 社区维护

Postgres.app

下载 Postgres 15+ 的最新版本

托管 PostgreSQL

pgvector 可在这些服务商上使用。

升级

安装最新版本(使用与初始安装相同的方式)。然后在每个需要升级的数据库中执行:

ALTER EXTENSION vector UPDATE;

可以通过以下命令查看当前数据库中的版本:

SELECT extversion FROM pg_extension WHERE extname = 'vector';

最后修改 2026-03-08: add extension catalog (baacba6)