PostgreSQL 向量数据和普通数据,到底有什么不一样?

由 John Doe 十月 16, 2026

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

目录

image

初探 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 的内存特性

目前业界向量搜索算法主要分为三大类:

  1. 基于聚类:代表为 IVF-Flat、IVF-PQ 等,先将向量聚合成多个簇,搜索时仅检索最近的若干簇
  2. 基于图:代表为 HNSW、DiskANN 等,将向量构建为多层导航图,通过贪心搜索快速定位最近邻
  3. 其他算法:例如局部敏感哈希(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%

总结:四个核心结论

  1. 向量搜索计算成本极高:运算开销与常规 B 树索引不在同一量级
  2. 向量数据天然大体积:单条向量接近 8KB 页大小,极易触发行外存储
  3. 向量搜索本质是近似检索:维度灾难下精确搜索不可行,需平衡召回率与速度
  4. 向量索引极度依赖内存:尤其是 HNSW 算法,内存不足会导致性能断崖式下跌

如果你正在基于 PostgreSQL 构建向量检索能力,非常推荐升级到 pgvector 新版本,通过半精度、稀疏向量等特性大幅降低资源开销。