news 2026/9/18 3:58:07

pgvector 快速上手:在 PostgreSQL 里存向量、建索引、跑相似查询

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pgvector 快速上手:在 PostgreSQL 里存向量、建索引、跑相似查询

pgvector 快速上手:在 PostgreSQL 里存向量、建索引、跑相似查询

【免费下载链接】pgvectorOpen-source vector similarity search for Postgres项目地址: https://gitcode.com/GitHub_Trending/pg/pgvector

如果你已经用 PostgreSQL 存业务数据,现在又想让模型产出的 embedding 也放进同一个库里、并能按"相似度"取最近邻,pgvector 就是为此而生的扩展。它给 Postgres 加了一个向量数据类型,再配上 HNSW、IVFFlat 两种索引,让你用普通 SQL 完成插入、过滤和最近邻查询,不需要单独维护一套向量数据库。

项目定位:它是什么,适合谁

pgvector 是一个开源的 PostgreSQL 扩展,当前默认版本 0.8.6,支持 Postgres 13 及以上。它的价值可以概括为三点:

  • 数据不搬家:向量列和业务字段(如用户 ID、分类、时间戳)在同一张表里,JOIN、事务、权限控制都能照常使用。
  • 查询方式不变:最近邻查询就是一句ORDER BY 距离 LIMIT n,任何会写 SQL 的语言(Python、Java、Go 等)都能直接驱动。
  • 精度可调:不加索引时是精确搜索,加了近似索引后在速度上换来一定的召回率损失,中间还有余量可以调。

它也不适合所有场景:如果你的数据量是几亿级别、且对写入吞吐和分布式扩展要求极高,单独的向量数据库可能更合适;pgvector 的舒适区大致在"几十万到几千万条向量、单机或主从 Postgres 能装下"的规模。

最小上手路径:从建库到第一次查询

前置条件:一台已装好 PostgreSQL 13+ 的机器(Linux、macOS 或 Windows 均可)。

第 1 步:拿到源码并编译安装。Linux/macOS 下只需三条命令,需要本地有gitmake和 Postgres 开发头文件:

git clone --branch v0.8.6 https://gitcode.com/GitHub_Trending/pg/pgvector cd pgvector && make && make install

Windows 用户则用 Visual Studio 的x64 Native Tools Command Prompt,设置好PGROOT后执行nmake /F Makefile.winnmake /F Makefile.win install,仓库里已附带Makefile.win

第 2 步:在目标数据库里启用扩展。注意这条要在每个想使用向量的数据库里各执行一次:

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]'); SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

如果第二条查询返回的两行中,[4,5,6]排在[1,2,3]前面,说明距离计算和排序都正常,扩展已经跑通。

核心用法拆解

用法一:按不同相似度选对距离算子

目的:模型输出的 embedding 各有特性,选错距离会让"相似"的含义跑偏。

pgvector 提供六种距离算子,最常用的是前三个:

算子含义适用场景
<->L2 距离(欧氏距离)通用默认选择
<#>负内积检索相关性,值越小越相似
<=>余弦距离只关心方向、不关心幅度的场景,如文本 embedding

关键步骤:距离只写在ORDER BY里即可生效,无需建索引:

-- 余弦相似度(取值 0~1,越大越相似) SELECT id, 1 - (embedding <=> '[3,1,2]') AS sim FROM items ORDER BY embedding <=> '[3,1,2]' LIMIT 5;

判断标准:用EXPLAIN看执行计划,出现Seq Scan且结果集可接受,就没问题;如果表已经很大、查询变慢,再进入用法二建索引。另注意<#>返回的是内积,要展示相似度时记得乘 -1。

用法二:为最近邻查询建索引

目的:表里的向量多了以后,逐行算距离会拖慢查询,索引的作用就是让查询从"全表扫描"变成"只扫一小片"。

HNSW 与 IVFFlat 怎么选

  • HNSW:建索引不需要表里有数据,查询速度快、召回率相对更好;代价是构建慢、占内存多。适合查询 QPS 高的在线服务。
  • IVFFlat:构建快、省内存,但建索引前必须先灌入一批数据(它内部要做聚类),且查询时靠probes参数调召回率。适合数据量大、查询压力中等、内存紧张的情况。

关键步骤:以最常用的 L2 距离为例,两种索引各一条命令:

-- HNSW:空表也能建 CREATE INDEX ON items USING hnsw (embedding vector_l2_ops); -- IVFFlat:建之前表里要有数据,lists 参考值 = 行数/1000(百万行以内) CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);

注意每个距离算子对应一个独立的索引:如果你既按<->查、又按<=>查,需要分别建vector_l2_opsvector_cosine_ops的索引。

判断标准

  • EXPLAIN (ANALYZE, BUFFERS)确认走了索引(HNSW 显示Index Scan using ...,IVFFlat 显示IVFFlat节点)。
  • 近似索引会导致同一条查询结果随时间变化(和 B-tree 索引行为不同),上线前心里要有数。
  • IVFFlat 想提高召回率,把ivfflat.probes从默认 1 调大(如 10),代价是变慢;HNSW 则调hnsw.ef_search(默认 40)。

用法三:带过滤条件的向量查询

目的:真实业务几乎总是"在某个分类/时间范围内找最相似的 N 条",而不是无条件搜索。

关键步骤:假设查询长这样——

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

处理思路按优先级排:

  1. 先给过滤列建普通 B-tree 索引CREATE INDEX ON items (category_id);当过滤条件命中行数很少时,Postgres 会先用 B-tree 缩出小集合再做精确距离计算,又快又准,这是最省事的方案。
  2. 过滤命中比例高时改用近似索引 + 迭代扫描:HNSW 默认只扫描 40 个候选,若过滤条件只放行 10% 的行,平均剩 4 条,可能不够填满LIMIT。开启迭代扫描可让索引自动多扫一些:
SET hnsw.iterative_scan = strict_order;
  1. 取值很少的过滤条件用部分索引:比如category_id只有 3 种值,可以给每个值建一个WHERE (category_id = ...)的部分索引,把索引体积拆小。

判断标准:过滤后仍能稳定返回LIMIT要求的条数,且EXPLAIN显示先用 B-tree(或部分 HNSW)缩小范围,再用向量索引排序,就是理想形态。

常见坑与建议

现象 1:装了扩展,但vector类型不存在。可能原因:CREATE EXTENSION vector只在某一个数据库执行过,而你现在连的是另一个库——Postgres 的扩展是按库生效的。 处理:在目标库里补执行一次CREATE EXTENSION vector;;用SELECT extversion FROM pg_extension WHERE extname = 'vector';验证当前库是否已装、版本多少。

现象 2:加了 HNSW 索引,但执行计划还是全表扫描。可能原因:ORDER BY里的距离算子和索引上声明的ops对不上(比如索引建的是vector_cosine_ops,查询却用了<->),或者查询里没有LIMIT。 处理:让算子和ops一一对应;同时确认查询形态是"距离排序 + LIMIT",否则优化器会认为全表扫描更划算。

现象 3:IVFFlat 建好索引后,召回率明显偏低。可能原因:建索引时表里数据太少,聚类中心不准;或者probes停在默认值 1,只查了 1/100 的列表。 处理:数据积累到接近真实规模后重建索引,把lists按行数重新估一遍;查询侧把ivfflat.probes提到sqrt(lists)附近再观察召回率与耗时的平衡点。

现象 4:大表建 HNSW 索引特别慢。可能原因:图结构装不进maintenance_work_mem,构建过程反复落盘。构建时 Postgres 会打印hnsw graph no longer fits into maintenance_work_mem的 NOTICE,这就是信号。 处理:临时调大该参数(如SET maintenance_work_mem = '8GB';),同时可把max_parallel_maintenance_workers从默认 2 往上加。注意别让这两个参数把机器内存吃光,构建完记得改回去。

延伸与收尾

跑通最小路径之后,仓库里有几块内容值得按顺序看:

  • sql/vector.sql:扩展的完整 DDL,向量类型、算子和两种访问方法都在这里注册,适合想理解"扩展到底往库里装了什么"的读者。
  • src/hnswbuild.csrc/ivfflat.c等源码文件:如果调参调不出理想召回率,可以从这里看构建和扫描逻辑;src/hnswvacuum.c则解释了索引如何跟随 VACUUM 收缩。
  • test/t/目录下的回归测试:文件名本身就是一份实验清单,如043_hnsw_iterative_scan.pl演示迭代扫描、045_hnsw_low_memory_build.pl演示低内存构建,照着这些场景做一轮压测,比凭空猜参数有效得多。
  • 半精度与二进制向量halfvec能把存储和内存占用砍半,bit类型配汉明距离适合做粗排初筛,等向量规模上去以后可以回来再看这两个方向。

【免费下载链接】pgvectorOpen-source vector similarity search for Postgres项目地址: https://gitcode.com/GitHub_Trending/pg/pgvector

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 3:57:09

Fluent Journal文件自动化后台批量计算实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 3:56:36

C++观察者模式实战:从原理、代码到工程化避坑指南

观察者模式在C里算得上是最实用的几个设计模式之一。它的核心价值就一句话&#xff1a;当某个对象状态发生变化时&#xff0c;所有依赖它的对象都能自动收到通知。听起来很玄乎&#xff0c;但你每天用的GUI按钮点击、游戏里的成就系统、行情软件的K线刷新&#xff0c;背后都是这…

作者头像 李华
网站建设 2026/9/18 3:56:12

计算机组成原理第七章:控制单元设计核心解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 3:56:07

HCCL故障定位思路:三阶段定界、多级检索关键字与故障码体系详解

HCCL故障定位思路&#xff1a;三阶段定界、多级检索关键字与故障码体系详解 【免费下载链接】hccl 集合通信库&#xff08;Huawei Collective Communication Library&#xff0c;简称HCCL&#xff09;是基于昇腾AI处理器的高性能集合通信库&#xff0c;为计算集群提供高性能、高…

作者头像 李华
网站建设 2026/9/18 3:55:53

MySQL启动报错:服务器退出未更新PID文件,一文讲透排查思路

“The server quit without updating PID file”&#xff0c;这句话我这些年见了太多次。有的是同事在测试环境卡了一下午&#xff0c;有的是生产环境凌晨三点被这条报错叫起来&#xff0c;还有的是刚装完MySQL&#xff0c;第一次启动就栽在这句话上。最气人的是&#xff0c;这…

作者头像 李华