---
title: 万字详解 RAG 向量索引算法和向量数据库
description: 深入解析 RAG 场景下的向量数据库选型与使用，涵盖向量索引算法（HNSW、IVFFLAT）、ANN 近似检索原理、pgvector 实践等高频面试考点。
category: AI 应用开发
head:
  - - meta
    - name: keywords
      content: RAG,向量数据库,向量索引,HNSW,IVFFLAT,pgvector,ANN,Embedding,相似度搜索
---

<!-- @include: @article-header.snippet.md -->

前段时间面某大厂的时候，面试官问我：“你们 RAG 系统的向量检索怎么做的？”

我当时回答：“用 MySQL 存 Embedding，查询时遍历计算相似度。”

面试官的表情已经说明问题了。我们当时知识库有 50 多万条 Chunk，每次查询都要全表扫描，平均响应时间 3 秒以上。对一个问答系统来说，这个延迟基本等于劝退用户。

后来才意识到，这就是典型的暴力搜索。Demo 阶段能跑，生产环境根本扛不住。真正上线时，至少要考虑向量数据库和 ANN 索引。

向量存储和向量索引是大多数 RAG 应用绕不开的基础设施。数据规模、延迟要求、召回要求一上来，靠遍历计算相似度很快就会出问题。

这篇文章围绕几个面试高频问题展开：

1. RAG 为什么需要向量数据库；
2. Embedding 和向量检索是什么关系；
3. 余弦距离、内积、欧氏距离怎么选；
4. 向量索引算法是什么，常见算法有哪些；
5. 项目里为什么用 HNSW，HNSW 和 IVFFLAT 有什么区别；
6. 有哪些向量数据库，为什么选择 PostgreSQL + pgvector，为什么不直接用 MySQL 来做。

## Embedding 和向量检索是什么关系？

向量数据库并不是直接理解文本。它存储和检索的是 Embedding。

Embedding 的过程是：把一段文本交给 Embedding 模型，模型输出一个固定维度的稠密向量。可以粗略理解成“文本语义坐标”。两段文本语义越接近，它们在向量空间里的距离通常也越近。

![Embedding 和向量检索是什么关系？](https://oss.javaguide.cn/github/javaguide/ai/rag/rag-embedding-vector-retrieval.png)

RAG 的向量检索链路可以简化成这样：

```text
文档 Chunk -> Embedding 模型 -> 文档向量 -> 写入向量数据库
用户问题 -> Embedding 模型 -> 查询向量 -> 检索最相似的 Top-K 文档向量
```

基础概念可以看 [RAG 基础篇](./rag-basis.md)。本文重点放在后半段：这些向量怎么高效存储、索引和检索。

## RAG 场景为什么需要向量数据库？

RAG（Retrieval-Augmented Generation）的核心是语义检索。系统把文档和用户问题都转成高维向量，再找出最相似的 Top-K 片段，作为 LLM 的上下文。

所以 RAG 场景里真正要解决的，不只是“能不能存 Embedding”，而是能不能在大规模高维向量里，低延迟找出最相关的 Top-K。

传统关系型数据库可以存向量，也可以通过函数或 SQL 表达式计算相似度。但如果没有专门的向量索引，通常只能全表扫描，很难支撑生产级低延迟检索。当 Chunk 数量达到几十万、百万甚至更高时，就需要引入向量数据库、向量搜索引擎，或者 PostgreSQL + pgvector 这类带向量索引能力的数据库扩展。

![RAG 场景为什么需要向量数据库？](https://oss.javaguide.cn/github/javaguide/ai/rag/rag-why-need-vector-store.png)

### 高维向量相似度搜索

Embedding 通常是 768 到 3072 维的稠密向量。没有向量索引时，即使数据库能计算余弦相似度、内积或欧氏距离，也很难在大规模数据上快速完成 Top-K 检索。

暴力搜索就是遍历全表计算距离，复杂度是 O(n)。以 100 万条 1024 维向量为例，单次查询大约要做：

```text
1,000,000 × 1,024 次乘法运算
```

实际延迟很容易到秒级，具体取决于硬件和实现。对实时问答系统来说，秒级延迟基本不可接受。

ANN（Approximate Nearest Neighbor，近似最近邻）检索就是为了解这个问题。向量数据库通过图导航、空间划分、量化等方式减少距离计算次数，不再每次都把所有向量算一遍。

ANN 的价值不在于永远返回 100% 精确的最近邻，而是在召回率、延迟和资源消耗之间做工程取舍。在合适的索引参数和硬件条件下，ANN 通常能把百万级向量检索从秒级暴力扫描优化到几十毫秒甚至更低。不过具体效果必须拿业务数据、Top-K、过滤条件、并发和召回率目标来测，不能只看理论复杂度。

| 指标     | 暴力搜索       | ANN 索引检索                     |
| -------- | -------------- | -------------------------------- |
| 检索方式 | 全量计算距离   | 只搜索候选集                     |
| 召回率   | 理论 100%      | 取决于索引类型和参数             |
| 延迟     | 数据量越大越慢 | 通常低很多                       |
| 代价     | 计算开销高     | 需要构建索引，占用额外内存或磁盘 |

上表只是数量级描述。实际性能和硬件规格、并发负载、数据分布、过滤条件、Top-K、索引参数（如 `ef_search`、`nprobe`）都有关系。选型和调参时，建议参考 [ann-benchmarks.com](https://ann-benchmarks.com)，更重要的是在自己的业务环境里验证。

### 大规模数据承载能力

RAG 知识库动辄几十万到亿级 Chunk。向量数据库通常会提供持久化、增量更新、分片、索引构建等能力。传统数据库虽然也能把向量当字段存进去，但没有专门索引和扩展能力时，规模一上来就会吃力。

### 语义检索和关键词检索有什么不同？

关键词检索和向量语义搜索解决的是两类问题。

| 检索方式     | 原理                     | 局限性                                                |
| ------------ | ------------------------ | ----------------------------------------------------- |
| BM25 关键词  | 字面匹配，基于词频统计   | 遇到同义词或改写容易失效，比如“退货”和“退款流程”      |
| 向量语义搜索 | Embedding 捕获语义相似性 | 能处理同义词、上下文和隐含意图，但依赖 Embedding 质量 |

文档切分策略和 Embedding 模型共同决定语义召回的理论上限，向量数据库负责在可接受延迟内把这个上限兑现出来。

生产级 RAG 通常还需要几类能力：

- 元数据过滤，比如 `WHERE category='Java' AND version>='v2'`，和向量相似度联合查询。
- 混合检索（Hybrid Search），把向量、BM25 和 RRF 融合起来。
- 动态更新，支持增量写入。但高频更新和删除会让向量索引出现膨胀、无效数据累积、召回或延迟波动，需要结合 `VACUUM`、`REINDEX`、执行计划和业务评测集持续观察。
- 权限和多租户隔离，这是企业级 RAG 的基本要求。

## 向量相似度和距离度量怎么选？

向量数据库做的不是关键词匹配，而是计算查询向量和文档向量之间的距离或相似度。RAG 场景常见的是余弦距离、内积和欧氏距离。

以 pgvector 为例，三种常用写法如下：

| 度量方式                    | pgvector 运算符 | operator class      | 特点                                                               | 适合场景                   |
| --------------------------- | --------------- | ------------------- | ------------------------------------------------------------------ | -------------------------- |
| 欧氏距离（L2 Distance）     | `<->`           | `vector_l2_ops`     | 衡量向量空间中的绝对距离，值越小越相似                             | 模型或索引明确按 L2 优化   |
| 内积（Inner Product）       | `<#>`           | `vector_ip_ops`     | pgvector 返回负内积，值越小越相似                                  | 向量已归一化、追求计算效率 |
| 余弦距离（Cosine Distance） | `<=>`           | `vector_cosine_ops` | 对向量长度不敏感，值越小越相似；余弦相似度可用 `1 - distance` 计算 | 文本语义检索、RAG 最常用   |

面试里如果被问“为什么 RAG 常用余弦相似度”，可以这样答：文本语义检索更关心方向是否接近，而不是向量长度本身；余弦距离对长度不敏感，更适合判断语义相似。如果 Embedding 模型输出已经归一化，内积和余弦在排序上通常等价，内积计算会更直接。

具体用哪个，不要凭感觉选。要看 Embedding 模型是否归一化、官方推荐的 metric，以及向量库索引是否支持对应 operator class。

实践里最容易踩的坑是：查询运算符必须和索引 operator class 一致。比如索引用的是 `vector_cosine_ops`，查询也要用 `<=>`，否则 PostgreSQL 可能无法使用这个向量索引。

## 什么是向量索引算法？

向量索引算法要解决的是一个很朴素的问题：在海量高维向量中，怎么快速找到和查询向量最相似的几个。

没有索引时，只能把数据库里的所有向量都比较一遍，这就是暴力搜索。百万、亿级数据下，这个延迟不可接受。

向量索引的目标，是提前把数据组织好，让查询时可以跳过绝大部分不相关向量，只在一个小得多的候选集里做精确比较。

用生活化一点的比喻：

- 没有索引：在整个城市挨家挨户找一个人。
- 有索引：先定位城区，再定位街道，再定位楼栋。

实践里，向量索引算法大致可以分成两类。

![向量索引算法分类](https://oss.javaguide.cn/github/javaguide/ai/rag/rag-vector-index-algorithms-Bjze1jhj.png)

多数时候我们谈向量索引，谈的是 ANN 算法。选对并调好 ANN 索引，直接影响 RAG 或向量搜索系统的性能和成本。调得好，性能提升可能是百倍甚至千倍；调不好，也可能召回掉得很难看。

### 精确最近邻（Exact Nearest Neighbor，ENN）

ENN 的目标是 100% 找到最相似的向量。KD-Tree、VP-Tree 这类传统空间树结构都属于这个方向。

问题在于，它们在低维空间里效果不错，比如 10 维以内。但 AI 领域的向量动辄几百上千维，很容易遇到维度灾难，最后退化得和暴力搜索差不多。

### 近似最近邻（Approximate Nearest Neighbor，ANN）

ANN 是现代向量检索的主流。它接受一个工程取舍：不保证 100% 找到绝对最近邻，而是以很高概率找到足够相似的结果，用一点召回损失换取几个数量级的速度提升。

常见 ANN 算法主要有三类：

- 基于图的算法，比如 HNSW。它把向量组织成多层网络图，查询时像导航一样在图上走。HNSW 通常能在查询速度和召回率之间取得比较好的平衡，是目前综合表现很强的一类算法。
- 基于量化的算法，比如 IVF-PQ。它通过聚类和压缩技术，把海量向量压缩成更小的数据，降低内存占用，更适合超大规模场景。
- 基于哈希的算法，比如 LSH。它通过特殊哈希函数，让相似向量有较大概率落入同一个桶，从而缩小搜索范围。

## 有哪些向量索引算法？

在 RAG 应用里，索引算法会直接影响召回率、响应延迟和资源消耗。

这里先区分两个层级：

| 层级             | 示例                        | 说明                               |
| ---------------- | --------------------------- | ---------------------------------- |
| 向量数据库       | Milvus、Qdrant、pgvector    | 负责向量存储、检索和管理的完整系统 |
| 其支持的索引算法 | HNSW、IVF-PQ、IVFFLAT、Flat | 决定检索性能与召回率的内部实现     |

主流索引算法可以先看这张表：

| 算法名称            | 原理机制                | 核心优势                      | 主要劣势                   | 更稳的适用描述                                                 |
| ------------------- | ----------------------- | ----------------------------- | -------------------------- | -------------------------------------------------------------- |
| Flat（暴力搜索）    | 遍历所有向量计算距离    | 100% 准确无损                 | 数据量大时查询很慢         | 小规模、低 QPS、离线评测、召回基准                             |
| HNSW（图索引）      | 分层导航的小世界图      | 查询快，召回率高              | 内存消耗大，构建耗时       | 中大规模、高召回、低延迟场景；百万级常见，千万级需重点评估内存 |
| IVFFLAT（倒排聚类） | 聚类 + 倒排索引桶       | 内存效率较好，构建较快        | 需前置训练，召回率略低     | 更关注内存和构建速度，可接受一定召回损失                       |
| IVF-PQ（乘积量化）  | 聚类 + 向量极致压缩     | 支持海量数据，开销低          | 精度损失较大               | 超大规模、内存敏感、可接受量化误差                             |
| IVF_RABITQ          | 聚类 + 随机旋转比特量化 | 内存占用低，召回率优于传统 PQ | 较新算法，生态支持仍在演进 | 超大规模、内存敏感、可接受量化误差                             |

关于 IVF_RABITQ 简单补一句。它是 2024 年提出的新一代量化算法，核心思路是 Random Rotation（随机旋转）+ Bit Quantization（比特量化）。相比传统 PQ 把向量切成子向量再分别聚类，RABITQ 会先对向量做随机旋转，让各维度分布更均匀，再把每个维度量化为 1 bit，只保留符号位。这样可以在保持较高召回率的同时显著压缩内存，并且距离计算可以用位运算加速。Milvus 2.6.x 中已经提供 `IVF_RABITQ` 索引类型。

## 你的项目使用的什么向量索引算法？

这里以 [《SpringAI 智能面试平台+RAG 知识库》](https://javaguide.cn/zhuanlan/interview-guide.html)项目为例。

项目里用的是 PostgreSQL 的 pgvector 扩展，并配置了 HNSW 索引。

为什么选 HNSW？因为在当前业务规模下，它在检索速度、召回率和工程复杂度之间比较均衡。

可以把 HNSW 理解成一个多层高速公路网络。

![HNSW 索引架构](https://oss.javaguide.cn/github/javaguide/ai/rag/rag-hnsw-architecture.png)

HNSW 的核心机制有三点。

第一是层次化构建。节点的最高层级由公式 `level = floor(-ln(random()) * mL)` 决定，其中 `mL` 是层级乘数。这会让越高层的节点数量指数级递减，形成类似金字塔的结构。

第二是贪心搜索。检索从顶层开始，每层都移动到距离查询点最近的邻居节点。

第三是由粗到精。上层负责快速定位语义区域，下层负责更精细地查找候选近邻。

这种查找方式能快速定位候选近邻，不需要像暴力搜索那样比较每个点。

HNSW 本质上是 ANN 算法，所以它追求的是速度和召回的平衡，不保证 100% 召回。但实践中可以通过参数调整把召回率做到比较高，是否足够要看业务评测集和最终答案质量。

HNSW 常见调优参数有三个：

- `m`：每个节点的最大连接数。`m` 越大，图越密，召回率越高，但构建时间和内存消耗也会上去。
- `ef_construction`：索引构建时的搜索范围。值越大，索引质量越好，但构建越慢。
- `ef_search`：查询时的搜索范围。这个运行时参数最重要，直接影响查询速度和召回率。

pgvector 的 HNSW 默认参数是 `m = 16`、`ef_construction = 64`、`ef_search = 40`。可以按下面这个方向调：

| 参数              | 常见范围 | 调大后的影响                             | 调优建议                                     |
| ----------------- | -------- | ---------------------------------------- | -------------------------------------------- |
| `m`               | 8-64     | 图更密，召回率更高，但内存和构建时间增加 | 先用默认值，召回不够再调到 24 或 32          |
| `ef_construction` | 64-256+  | 索引质量更好，但构建更慢                 | 离线构建能接受更慢时再调大                   |
| `ef_search`       | 40-200+  | 查询召回更高，但延迟增加                 | 最适合在线调参，用评测集找召回率和延迟平衡点 |

一个实用做法是先固定 `m` 和 `ef_construction` 建好索引，再通过会话参数调 `ef_search`：

```sql
SET hnsw.ef_search = 100;
```

然后用 `EXPLAIN ANALYZE` 确认是否命中索引，再用一批人工标注问题对比不同 `ef_search` 下的召回率、延迟和最终答案质量。`ef_search` 不需要无限调大，达到业务可接受召回后就该停下来，不然只是用延迟和 CPU 换一点很小的收益。

扩展性也要提前想。HNSW 很吃内存。如果未来数据规模增长到千万甚至亿级，或者写入吞吐要求更高，HNSW 的内存占用和构建成本可能会变成瓶颈。

这时可以考虑 IVFFLAT。IVFFLAT 基于倒排索引思想，把向量空间聚类成多个桶，从而缩小搜索范围。也可以引入 Milvus 这类专业向量数据库，它们在分布式和大规模场景下更成熟。

还有一个容易忽略的点：过滤条件。

pgvector 的 HNSW 索引遇到 `WHERE` 过滤条件时，要重点看执行计划。近似索引通常会先按向量距离找候选，再应用过滤条件。如果过滤条件很严格，最终结果可能少于 Top-K 预期，某些查询形态下甚至会退化成更慢的扫描。

比如查询“返回 10 条相似文档中 `category='Java'` 的记录”，如果候选集中只有 3 条满足条件，那就只能返回 3 条。

常见处理方式有几种：

1. 增大候选集：设置更大的 `ef_search` 或 `LIMIT`，让更多候选进入过滤阶段。
2. 预过滤（Pre-filtering）：先按元数据过滤，再做向量搜索，但可能导致索引失效，退化为暴力搜索。
3. 部分索引（Partial Index）：PostgreSQL 支持带条件的 HNSW 索引，比如 `CREATE INDEX ... WHERE category = 'Java'`，但需要为常见过滤条件创建独立索引。
4. 迭代索引扫描（Iterative Index Scan）：pgvector 0.8.0+ 支持过滤后结果不足时继续扫描更多索引，缓解“先 ANN 后过滤导致 Top-K 不足”的问题。但它仍然需要配合 `hnsw.max_scan_tuples`、`ivfflat.max_probes` 等参数控制成本。

## HNSW 索引和 IVFFLAT 索引有什么区别？

这两者的核心区别很简单：HNSW 靠图的连通性找邻居，IVFFLAT 靠聚类缩小搜索范围。

HNSW 会构建多层图结构。查询时像在高速公路上走，先在上层做大跨度跳跃，再到底层做局部精细搜索。它的优点是查询快，召回率通常较高且稳定；缺点是内存消耗大，除了原始向量，还要存大量节点连接关系，索引构建通常也更慢。

IVFFLAT 用 K-Means 把向量空间切成多个桶。查询时先找最近的几个桶，只在桶内做暴力搜索。它的优点是内存更友好，结构简单，构建通常更快；缺点是在相同召回目标下，查询性能和稳定性通常不如 HNSW。如果数据分布变化明显，还可能需要重新训练聚类中心。

| 特性       | HNSW（图索引）                                | IVFFLAT（倒排聚类）                      |
| ---------- | --------------------------------------------- | ---------------------------------------- |
| 底层原理   | 层次化小世界图结构                            | 聚类 + 倒排桶结构                        |
| 查询速度   | 通常更快，召回更稳定                          | 取决于 `lists` 和 `probes`               |
| 内存消耗   | 较高，原始向量 + 图连接指针                   | 通常低于 HNSW                            |
| 构建速度   | 较慢，需要逐个节点插入                        | 通常更快，但需要聚类训练                 |
| 数据动态性 | 增量添加方便，大量更新 / 删除后需观察索引健康 | 数据分布变化明显时可能需要重建索引       |
| 适用场景   | 中大规模、高召回、低延迟场景                  | 更关注内存和构建速度，可接受一定召回损失 |

怎么选？

追求低延迟和高召回，并且服务器内存足够，优先 HNSW。更关注内存、构建速度，能接受一定召回损失，并愿意调 `lists` / `probes`，可以考虑 IVFFLAT。

## 有哪些向量数据库？

向量数据库选型没有银弹，适合项目的才是好方案。

### 传统数据库扩展

代表方案包括 PostgreSQL + pgvector，以及 MongoDB Atlas Vector Search。

这类方案的优势是技术栈统一，不需要额外引入一套数据库系统；向量数据和业务数据可以在同一事务里管理；团队已有 SQL 经验可以复用；也方便把 SQL 过滤条件和向量搜索组合起来。

它适合项目初期或中小型项目。尤其是业务数据和向量数据需要强一致性、能在同一个事务里管理时，PostgreSQL + pgvector 的优势很明显。对已经在用 PostgreSQL 的团队来说，学习和运维成本都低。

### 搜索引擎演进

代表方案是 Elasticsearch 和 OpenSearch。

这类方案的优势是混合搜索能力强，可以把 BM25 关键词检索和向量语义搜索结合起来。它也保留了传统搜索引擎在长文本、分词、高亮、聚合分析上的优势，并且分布式架构成熟。

如果你的业务本来就依赖关键词检索，比如电商搜索、文档检索、复杂过滤和聚合分析，或者团队已经有 ES 技术栈，那么复用 ES / OpenSearch 的向量能力会比较自然。

### 原生专业向量数据库

代表方案包括 Milvus、Weaviate、Qdrant。

Milvus 功能比较全面，社区也大；Weaviate 内置 AI 模块，支持 GraphQL 查询，易用性不错；Qdrant 用 Rust 编写，内存效率高，过滤能力也比较强。

这类数据库专门为向量检索优化，通常支持多种索引算法，比如 HNSW、IVF、LSH 等，在分区、多租户、动态更新、距离度量方面也更专业。

当向量规模达到亿级甚至更高，或者对 QPS 和延迟要求很苛刻时，原生向量数据库通常会比 pgvector 更合适。代价也很明确：多一套系统，就多一套运维、监控、备份和学习成本。

### 云托管向量数据库服务

代表方案包括 Pinecone、Zilliz Cloud、Weaviate Cloud 等。

它们的优势是运维负担低，上线快，通常提供自动扩缩容和高可用 SLA。预算充足、团队不想自运维时，这类方案很有吸引力。

不过“托管”不等于不用管。索引参数、召回评测、权限隔离、成本监控还是要自己负责。

## 向量数据库怎么选？

可以先按下面这张图粗略判断：

```mermaid
flowchart TB
    classDef gateway fill:#7B68EE,color:#FFFFFF,stroke:none,rx:10,ry:10
    classDef primaryDB fill:#E99151,color:#FFFFFF,stroke:none,rx:10,ry:10
    classDef search fill:#16A085,color:#FFFFFF,stroke:none,rx:10,ry:10
    classDef infra fill:#9B59B6,color:#FFFFFF,stroke:none,rx:10,ry:10
    classDef success fill:#4CA497,color:#FFFFFF,stroke:none,rx:10,ry:10

    Start["向量数据库选型"]:::gateway
    Ops{"不想自运维？"}:::gateway
    Cloud["Pinecone / Zilliz Cloud<br/>Weaviate Cloud"]:::infra
    Existing{"已有 PG / ES？"}:::gateway
    ExistingStack["pgvector 或 ES 向量检索"]:::primaryDB
    Scale{"百万级以上<br/>且向量能力要求高？"}:::gateway
    Pro["Milvus / Qdrant / Weaviate"]:::search
    Hybrid["混合检索优先<br/>ES / Weaviate / pgvector + pg_bm25"]:::success

    Start --> Ops
    Ops -->|是| Cloud
    Ops -->|否| Existing
    Existing -->|是| ExistingStack
    Existing -->|否| Scale
    Scale -->|是| Pro
    Scale -->|否| Hybrid

    linkStyle default stroke-width:2px,stroke:#333333,opacity:0.8
```

更口语一点：

- 数据规模小于 100 万，团队已有 PostgreSQL，优先 pgvector。
- 数据规模小于 100 万，团队已有 Elasticsearch / OpenSearch，优先复用 ES 向量检索和 BM25 混合检索。
- 数据规模在百万到十亿级，并且需要专业向量能力，考虑 Milvus、Qdrant、Weaviate。
- 不想自运维，考虑 Pinecone、Zilliz Cloud、Weaviate Cloud。
- 强依赖混合检索，优先 ES / OpenSearch、Weaviate，或者 PostgreSQL + pgvector + pg_bm25 的组合。

## 你为什么选择 PostgreSQL + pgvector？

这里以 [《SpringAI 智能面试平台+RAG 知识库》](https://javaguide.cn/zhuanlan/interview-guide.html)项目为例。这个项目需要同时存结构化数据，比如简历、面试记录，也要存向量数据，也就是文档 Embedding。

方案对比如下：

| 方案                    | 优点                     | 缺点                       | 适用规模       |
| ----------------------- | ------------------------ | -------------------------- | -------------- |
| PostgreSQL + pgvector   | 一套数据库搞定，运维简单 | 百万级以上性能下降明显     | < 100 万向量   |
| PostgreSQL + Milvus     | 向量检索性能更好         | 多一个组件，运维复杂度增加 | 100 万 - 10 亿 |
| Pinecone / Zilliz Cloud | 全托管，低运维           | 成本高，数据在第三方       | 任意规模       |

选择 pgvector 的理由主要有几个。

第一，架构简单。不引入额外组件，部署和运维复杂度低。

第二，性能够用。HNSW 索引的速度和召回率能满足当前业务要求。

第三，事务一致性好。向量数据和业务数据在同一个数据库里，天然支持事务。

第四，SQL 查询方便。可以结合 `WHERE` 条件过滤，但要注意过滤条件可能影响向量索引命中，所以必须检查执行计划。

```sql
-- pgvector 余弦相似度搜索示例
-- <=> 是余弦距离运算符（0 = 完全相同，2 = 完全相反）
-- 余弦相似度 = 1 - 余弦距离
SELECT content, 1 - (embedding <=> $1) as cosine_similarity
FROM vector_store
WHERE metadata->>'category' = 'Java'
ORDER BY embedding <=> $1  -- 按距离升序，越小越相似
LIMIT 5;

-- ⚠️ 关键前提：查询时使用的距离运算符必须与创建 HNSW 索引时指定的
-- operator class（例如 vector_cosine_ops）严格保持一致，否则查询将
-- 无法命中索引，直接退化为全表扫描。
-- 验证方式：EXPLAIN ANALYZE 检查执行计划是否包含 Index Scan。
```

## pgvector 实践细节有哪些？

pgvector 的核心不是“能不能存向量”，而是索引、距离度量和查询语句必须配套。

### HNSW 索引创建示例

```sql
-- embedding 类型示例：vector(1536)
CREATE INDEX idx_document_embedding_hnsw
ON document_chunk
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
```

如果查询用的是 `<=>` 余弦距离，索引就要使用 `vector_cosine_ops`。如果查询用 `<->`，索引就要改成 `vector_l2_ops`。

### IVFFLAT 索引创建示例

```sql
CREATE INDEX idx_document_embedding_ivfflat
ON document_chunk
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);

-- 查询时控制扫描多少个聚类桶
SET ivfflat.probes = 10;
```

IVFFLAT 需要先有一定数据量再建索引，因为它要先聚类。`lists` 可以从 `rows / 1000` 到 `sqrt(rows)` 之间起步评估；`probes` 越大，召回率越高，查询也越慢。

### 索引维护

大量删除或更新后，向量索引可能出现膨胀、无效数据累积，甚至召回和延迟波动。可以在业务低峰期做 `VACUUM`、`REINDEX`，同时观察执行计划和业务评测集。

`VACUUM` 仍然重要，但它不是万能的召回率修复工具。向量索引的健康状况，要通过查询延迟、召回率评测和执行计划一起看。

每次调整距离运算符、operator class、过滤条件或索引参数后，都要用 `EXPLAIN ANALYZE` 检查是否命中索引。

### 版本特性

- pgvector 0.5+ 支持 HNSW 索引。
- pgvector 0.7+ 增加了 `halfvec`、`sparsevec`、`bit` 等类型和更多距离能力，适合进一步压缩存储或处理稀疏向量。
- pgvector 0.8.0+ 支持 iterative index scans，可以在过滤后结果不足时继续扫描更多索引，缓解 Top-K 不足问题。生产环境建议固定版本，升级前跑回归评测。

## 为什么不选择 MySQL 搭配向量数据库？

PostgreSQL 在这类场景里最大的优势，是扩展能力强。开发者可以在不改数据库内核的情况下，通过扩展补齐很多能力。

比如：

- AI 向量检索：pgvector 扩展，和 PostgreSQL 原生生态结合紧密，支持 ACID、JOIN、备份恢复和 SQL 过滤，适合中小规模、希望简化技术栈的 RAG 项目。
- 全文搜索：内置 `tsvector` 能满足基础需求，更高级的可以考虑 pg_bm25。
- 时序数据：TimescaleDB。
- 地理信息：PostGIS。

这种“一套 PG 承担多种基础能力”的模式，对中小规模项目很友好。先用 PostgreSQL 简化技术栈，等数据规模、QPS、多租户隔离要求继续上升，再拆出 Elasticsearch、Milvus、Qdrant、Weaviate 等专业组件，会更稳。

MySQL 这边要分版本看。MySQL 8.x 系列，包括 8.4 LTS，没有官方 `VECTOR` 数据类型。MySQL 9.x 已经引入 `VECTOR` 数据类型和相关函数，但从官方能力看，它更偏向向量存储和基础函数支持，还不是成熟的生产级 ANN 检索方案。

如果项目已经深度绑定 MySQL，可以继续用 MySQL 存业务数据，再搭配 pgvector、Milvus、Qdrant、Weaviate、Elasticsearch / OpenSearch 等外部向量检索组件。没必要为了 RAG 强行把所有东西塞进 MySQL。

![VECTOR 列不能用作任何类型的键，包括主键、外键、唯一键和分区键](https://oss.javaguide.cn/github/javaguide/ai/rag/mysql9-vector-cannot-be-used-as-any-type-of-key.png)

关于 MySQL 和 PostgreSQL 的详细对比，可以参考我写的这篇文章：[MySQL vs PostgreSQL，如何选择？](https://mp.weixin.qq.com/s/APWD-PzTcTqGUuibAw7GGw)。

<!-- @include: @rag-project.md -->

## 总结

向量存储和向量索引是 RAG 系统绕不开的基础设施。选型选错了，后面很容易变成“检索慢、召回差、成本高”。

没有专门向量索引时，大规模高维向量 Top-K 检索通常只能全表扫描。ANN 索引通过牺牲一点精确性，在召回率、延迟和资源消耗之间做工程取舍。

主流索引算法里，Flat 是暴力搜索，适合小规模、低 QPS、离线评测和召回基准；HNSW 是图索引，查询快、召回高，但内存消耗大；IVFFLAT 是倒排聚类，内存更友好、构建较快，但需要调参并接受一定召回损失；IVF-PQ 通过乘积量化支持海量数据，但会带来精度损失。

HNSW 更适合低延迟和高召回，IVFFLAT 更适合内存和构建成本敏感的场景。数据库选型上，PostgreSQL + pgvector 适合中小规模，Milvus、Qdrant、Weaviate 更适合大规模或专业向量检索，Pinecone、Zilliz Cloud 适合低运维场景。

面试里常问这些：

- 什么是 Embedding？为什么需要把文本转成向量？
- RAG 场景为什么需要向量数据库？
- 余弦相似度和欧氏距离有什么区别？RAG 场景下用哪个？
- ANN 算法为什么可以接受不是 100% 精确的结果？
- 有哪些向量索引算法？各自优缺点是什么？
- HNSW 和 IVFFLAT 有什么区别？
- HNSW 的 `ef_search` 参数怎么调？调大和调小分别会怎样？
- 向量数据库和传统数据库最核心的区别是什么？
- 如果向量数据从 100 万增长到 1 亿，架构上需要做什么调整？
- pgvector 的 HNSW 索引在什么情况下会失效或退化为更慢的扫描？
- 为什么选择 PostgreSQL + pgvector？

动手时建议先把 HNSW 的图结构、IVF 的聚类原理理解清楚，再用 pgvector 或 Milvus 搭一个最小 Demo，比较不同索引参数下的召回率和延迟。`ef_search`、`nprobe` 这些参数不要凭感觉调，最好拿真实业务问题做评测。

向量数据库选型和索引调优，直接决定 RAG 系统能不能在生产环境站稳脚跟。选错了，就是检索慢、召回差、成本炸三连。
