← 系统工具使用

系统工具使用

pgvector 向量索引:精确扫、HNSW、IVFFlat

·系统工具使用

pgvector 官方只有两种向量索引:HNSW 和 IVFFlat。再加上默认的「不建向量索引 = 精确扫描」,实际就这三档。halfvec / bit / sparsevec 是存储类型,不是第三种索引。

镜像 pgvector/pgvector:pg16 能力对齐 0.8.x:两种 ANN,加上 0.8 起的 iterative scan。

官方原话可以记成两句:默认精确、完美召回;一旦加上近似索引,同一条 SQL 的结果会变。HNSW 速度–召回更好、构建更慢更吃内存;IVFFlat 反过来。

一句话: pgvector 没有第三种能「又快又全准」的向量索引。在线 Top-K 用 HNSW;要「阈值以上一张不漏」,只能精确扫(或先把身份落成标量再走 B-tree)。

先分清三层

算法、列类型、距离算子是三件事,建索引时不要混在一起。

① 检索算法(索引方法,只有这些)
     精确扫(无向量索引) |  HNSW  |  IVFFlat

② 向量类型(列怎么存)
     vector(512)  float32
     halfvec      float16
     bit          二值
     sparsevec    稀疏(仅 HNSW 能建索引)

③ 距离(operator class,每种索引要单独建)
     <=> 余弦   <-> L2   <#> 内积   <+> L1(仅 HNSW)
     <~> Hamming / <%> Jaccard(bit)

建索引必须写成 USING hnsw (col vector_cosine_ops) 这种。换距离 = 再建一个索引,不是新算法。

对照

精确扫(无 ANN) HNSW IVFFlat
本质 逐条算距离 分层小世界图 k-means 切桶,只探近的桶
Top-K 精确 近似 近似
阈值以上全部 精确 不保证 不保证(probes=lists 时约等于精确,规划器往往改走精确扫)
构建 无 慢,吃内存;空表就能建 快、省内存;必须先有数据做 k-means
查询 O(N),最慢但全准 同召回下通常比 IVF 快 同资源下召回/延迟一般不如 HNSW
插入 普通 heap 图要维护,持续写入会胀 新点塞进旧质心,数据分布变了召回掉,要重建
核心旋钮 无 构建 m(默认 16)、ef_construction(64);查询 ef_search(默认 40,上限 1000) 构建 lists;查询 probes(默认 1)
维度上限 vector 存 16000 维;索引(HNSW/IVF)只到 2000 halfvec 到 4000,bit 到 64000,sparsevec 仅 HNSW(最多 1000 个非零) 无 sparsevec / L1 / Jaccard;Hamming(bit)可以
主流规模 < 10 万 常驻在线;一天分区 50 万~百万也能做离线/秒级查询 10 万~千万 在线 Top-K;再大靠分区或量化 100 万~千万、偏静态、能接受重建
主流用法 底库、评测 ground truth、范围全量 RAG / 以图搜人 / GetTracks 一次性灌库、内存紧、召回要求一般

各自怎么用

1. 精确扫

完整到访、评测、「阈值以上一张不漏」该用这一档。不要建 HNSW;高选择性的 WHERE 先走 B-tree 裁子集,再在子集上精确算。

-- 先裁子集,再精确扫
CREATE INDEX ON t_ai_face_trajectories_2026_09_18 (capture_time);

SELECT id, 1 - (face_feature <=> $q) AS sim
FROM t_ai_face_trajectories_2026_09_18
WHERE capture_time >= $start AND capture_time < $end
  AND 1 - (face_feature <=> $q) >= $threshold;

如果规划器硬要走向量索引,再临时关掉它(仅本事务):

BEGIN;
SET LOCAL enable_indexscan = off;
-- 上面的 SELECT
COMMIT;

2. HNSW

在线只要最近邻时的默认选项。空表可建,适合持续 INSERT。

CREATE INDEX ON t_ai_face_trajectories
  USING hnsw (face_feature vector_cosine_ops)
  WITH (m = 16, ef_construction = 64);

SET LOCAL hnsw.ef_search = 100;   -- 至少 ≥ LIMIT,需要更高召回再往上调
SELECT ... ORDER BY face_feature <=> $q LIMIT 100;

3. IVFFlat

适合「先灌满再查」。新项目默认选 HNSW,IVF 是明确要省构建 / 内存时才用。

-- 官方起点:≤100 万 lists ≈ rows/1000;>100 万 lists ≈ sqrt(rows)
-- probes 起点 ≈ sqrt(lists)
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops)
  WITH (lists = 1000);
SET LOCAL ivfflat.probes = 32;

不是索引、但常被当成「第四种」

东西 是什么 干什么
halfvec 索引 对 float32 列建 USING hnsw ((col::halfvec(512)) halfvec_cosine_ops) 索引减半、可到 4000 维;召回略降,常再精确重排
bit / 二值量化 列或表达式变成 bit,Hamming 极致压缩、粗筛;人脸 512 维一般不靠它当主检索
iterative_scan 查询参数,0.8+ ANN 被 WHERE 滤光后继续探;有上限,不能当全量范围索引
分区 / 部分索引 日分区、WHERE camera_id=... 先裁 N,再 ANN 或精确扫。人脸副表已经按天分区
pgvectorscale DiskANN Timescale 另一个扩展 不是 pgvector 自带

怎么选

N 小、必须全准、或「阈值以上一张不漏」
    → 精确扫(可加日分区)
    → 完整到访、评测、Faiss 底库那档

N 大、只要最近的 K 个、持续写入
    → HNSW + LIMIT ≤ ef_search
    → GetTracks / 快速寻人(现状)

N 大、几乎只读、内存紧、能接受定期 REINDEX
    → IVFFlat
    → 没必要为「全部返回」去用

在线 Top-K 用 HNSW;要 MySQL 那种全部返回,只能精确扫。两条路径不要指望用同一种 ANN 兼顾。