由 John Doe 十月 16, 2026
PostgreSQL 中向量数据的底层特性,与常规数据类型存在本质差异。让我们通过这些差异,来了解下向量检索的核心逻辑。
目录

初探 pgvector:一个反直觉的性能发现
当我们深入 pgvector 的 HNSW 搜索逻辑时,会发现每筛选一个候选向量节点,代码就会执行 3 次内存分配:1 次分配候选结构体、2 次分配配对堆节点。
放在常规 B 树索引场景里,这种高频内存分配会让性能慢到离谱;但在 HNSW 向量搜索中,这点开销几乎可以忽略不计。
第一条核心结论:向量搜索的计算成本非常高。 高维距离计算本身的运算量远大于内存分配这类常规操作,这也是向量检索和普通数据查询最直观的性能差异。
向量到底是什么?天生的 “大块头” 数据
很多人听过向量,但未必清楚它的物理形态:向量本质是一组浮点数组成的数组,数组中的每个数值就是一个 “维度”。维度的数量和含义完全由业务场景决定:
- 例如 OpenAI 的
text-embedding-ada-002模型,输出为 1536 维向量 - 单条 1536 维的向量,数据量大约是 6KB
第二条核心结论:向量数据的体积极其庞大。 PostgreSQL 默认数据页大小为 8KB,单条向量就几乎占满一整页。这直接限制了 pgvector 可支持的最大维度数;同时包含向量的行数据极易触发 TOAST 机制,被存储到行外空间。
同样是 “大体积数据类型”,向量和 JSON、二进制 Blob 有本质区别:
- JSON 数据:GIN 索引会把文档拆分为键值对分别索引,但这套逻辑对向量完全失效,向量搜索必须所有维度联合计算,无法拆分处理
- 二进制 Blob、长文本:这类数据通常仅做存储与读取,不需要复杂的索引检索
向量搜索 = 最近邻搜索,但维度天差地别
向量搜索的本质是最近邻搜索:输入一个查询向量,在数据库中找出与它距离最近、相似度最高的一批向量。
对应到 SQL 语法非常简洁:
SELECT id
FROM items a
ORDER BY embedding <=> $1
LIMIT 10;
其中 <=> 是余弦距离运算符,$1 为传入的查询向量。
实际检索效果示例
在维基百科数据集里,以 “抛物面反射器” 的向量为基准做检索,返回的前 5 条结果高度相关:
| 条目名称 | 余弦距离 |
|---|---|
| Parabolic reflector(抛物面反射器) | 0 |
| Parabolic antenna(抛物面天线) | 0.0742 |
| Parabolic microphone(抛物面麦克风) | 0.0897 |
| Satellite dish(卫星天线) | 0.1268 |
| Reflector (antenna)(天线反射器) | 0.1272 |
很多人会问:这不就是 PostGIS 的空间最近邻搜索吗? 两者逻辑相似,但维度量级完全不同:
- 地理空间数据仅 2~3 个维度
- 向量数据通常为 100~5000 个维度
传统 B 树、kd 树、分区等索引方法,在高维空间中会彻底失效,这就是计算机领域著名的维度灾难(Curse of Dimensionality)。
维度灾难:为什么向量搜索只能是 “近似” 的
人类的空间直觉建立在三维世界,这套认知在高维空间里完全不成立。在数百上千维的空间中,精确最近邻搜索的计算成本会指数级上升,达到工业场景完全不可用的程度。
第三条核心结论:工业级向量搜索都是近似最近邻(ANN)。 所有向量索引的核心设计,都是在召回率(准确率)和查询速度之间做权衡。
从实际效果看,近似搜索的结果与精确结果差异极小。上面的示例中,近似结果的距离值和精确值仅在小数点后第四五位有差别,完全可以满足绝大多数业务场景。
经典痛点:向量搜索的 “过滤难题”
如果在向量搜索时叠加过滤条件,比如:
SELECT … WHERE title like 'A%' ORDER BY distance LIMIT 10;
会出现一个反直觉的现象:
- 走向量索引:仅返回 1 条符合条件的结果
- 走全表扫描:能返回 10 条符合条件的结果
这是因为向量索引是按距离排序的候选集,过滤条件会大幅削减有效候选,导致索引检索结果不足,这也是当前向量数据库领域的核心优化方向之一。
主流向量算法与 HNSW 的内存特性
目前业界向量搜索算法主要分为三大类:
- 基于聚类:代表为 IVF-Flat、IVF-PQ 等,先将向量聚合成多个簇,搜索时仅检索最近的若干簇
- 基于图:代表为 HNSW、DiskANN 等,将向量构建为多层导航图,通过贪心搜索快速定位最近邻
- 其他算法:例如局部敏感哈希(LSH)等
其中 pgvector 默认支持的 HNSW 是当前最主流的算法,但它有一个非常鲜明的特性: HNSW 索引构建是纯内存算法。
构建索引时会随机访问整个索引结构,一旦索引大小超出 maintenance_work_mem,构建性能会急剧下降,PostgreSQL 会给出明确提示:
NOTICE: hnsw graph no longer fits into maintenance_work_mem after 9216 tuples
HINT: Increase maintenance_work_mem to speed up builds.
不仅是构建阶段,查询时 HNSW 也会随机访问上百个数据页,对内存缓存的压力远高于普通 B 树索引。
pgvector 重磅优化:三种全新向量类型
针对向量体积大、内存占用高的痛点,pgvector 0.7.0 版本推出了三种更轻量的向量数据类型:
- vector:原生类型,32 位单精度浮点数
- halfvec:新增,16 位半精度浮点数,体积直接减半
- bit vector:新增,每个维度仅用 1 bit 存储,极致压缩
- sparsevec:新增,仅存储非零维度,适配稀疏向量场景
更小的数据类型带来三项直接收益:索引体积缩减、内存占用降低、缓存命中率提升。
halfvec 实测效果
索引构建速度
- 原生 vector:6 分 42 秒
- halfvec:5 分 15 秒 构建耗时缩短约 22%
表数据体积
- 原生 vector 表:8319 MB
- halfvec 表:4368 MB 存储空间减少接近 50%
总结:四个核心结论
- 向量搜索计算成本极高:运算开销与常规 B 树索引不在同一量级
- 向量数据天然大体积:单条向量接近 8KB 页大小,极易触发行外存储
- 向量搜索本质是近似检索:维度灾难下精确搜索不可行,需平衡召回率与速度
- 向量索引极度依赖内存:尤其是 HNSW 算法,内存不足会导致性能断崖式下跌
如果你正在基于 PostgreSQL 构建向量检索能力,非常推荐升级到 pgvector 新版本,通过半精度、稀疏向量等特性大幅降低资源开销。