主题
5.1 为什么需要向量索引
10万条向量的全表扫描需要数百毫秒——加上索引后只需要几毫秒
这一节在讲什么?
当你的 documents 表只有几百条记录时,ORDER BY embedding <=> query_vec LIMIT 5 是瞬间完成的。但当数据量增长到十万、百万条时,这条 SQL 会变得非常慢——因为 PostgreSQL 必须计算查询向量与每一行向量的距离,然后排序取 top-5。这就是"暴力搜索"(Brute Force),时间复杂度是 O(N×d),其中 N 是行数、d 是向量维度。向量索引通过牺牲少量精度(召回率),换取数量级的速度提升。这一节我们要理解为什么需要向量索引、pgvector 支持哪些索引类型、以及何时该建索引。
暴力搜索的瓶颈
sql
-- 暴力搜索:计算每行的距离并排序
SELECT id, content, embedding <=> '[0.1, ...]' AS distance
FROM documents
ORDER BY embedding <=> '[0.1, ...]'
LIMIT 5;对于 N 条 d 维向量,暴力搜索需要:
- N 次距离计算(每次 O(d))
- 排序 N 个距离值(O(N log N))
- 总时间复杂度:O(N × d)
数据量与暴力搜索延迟参考(384维向量):
1K 条: ~2ms
10K 条: ~20ms
100K 条: ~200ms
1M 条: ~2000ms (2秒)
10M 条: ~20000ms (20秒)当数据量超过 10K 条时,暴力搜索的延迟就开始影响用户体验了。向量索引的目标是把搜索复杂度从 O(N) 降到 O(log N) 或 O(√N),代价是可能遗漏少量真正最相似的结果(召回率 < 100%)。
近似最近邻(ANN)的权衡
向量索引使用的是"近似最近邻"(Approximate Nearest Neighbor, ANN)算法——它不保证找到真正的 top-K 最相似向量,但以极高的概率找到足够相似的结果。核心权衡是:
┌──────────────────────────────────────────────────────────────────┐
│ ANN 的三维度权衡 │
│ │
│ 召回率(Recall): 搜索结果中有多少是真正的 top-K │
│ ↑ 越高越好,但通常 95% 就够了 │
│ │
│ 延迟(Latency): 单次查询的耗时 │
│ ↑ 越低越好,RAG 场景建议 < 100ms │
│ │
│ 内存(Memory): 索引占用的内存 │
│ ↑ 越少越好,但 HNSW 通常需要 2~3x 向量数据大小 │
│ │
│ 三者不可兼得: │
│ 高召回 + 低延迟 → 需要更多内存 │
│ 低内存 + 高召回 → 需要更长延迟 │
│ 低延迟 + 低内存 → 召回率下降 │
└──────────────────────────────────────────────────────────────────┘pgvector 支持的两种索引
| 索引 | 算法 | 搜索复杂度 | 增量更新 | 内存占用 | 推荐场景 |
|---|---|---|---|---|---|
| IVFFlat | 倒排文件 + 平面量化 | O(√N) | 需重建 | 较小 | 数据量大且稳定 |
| HNSW | 分层导航小世界图 | O(log N) | 支持 | 较大 | 数据量中等且频繁更新 |
下一节我们将分别深入这两种索引的原理和参数调优。
何时建索引
不是所有场景都需要向量索引。经验法则:
| 数据量 | 建议 |
|---|---|
| < 1K | 不需要索引,暴力搜索足够快 |
| 1K ~ 10K | 可选,暴力搜索通常 < 20ms |
| 10K ~ 100K | 建议建索引,暴力搜索 > 100ms |
| > 100K | 必须建索引,暴力搜索不可接受 |
本章小结
向量索引是 pgvector 在大数据量下保持快速搜索的关键。核心要点回顾:第一,暴力搜索的时间复杂度是 O(N×d),10万条 384 维向量的全表扫描需要约 200ms;第二,ANN 算法通过牺牲少量召回率换取数量级的速度提升;第三,pgvector 支持两种索引——IVFFlat(O(√N))和 HNSW(O(log N));第四,数据量 < 10K 不需要索引,> 100K 必须建索引。
下一节我们将深入 IVFFlat 索引的原理和参数调优。