首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >大规模向量库的索引选型与查询性能调优:Milvus 实战指南

大规模向量库的索引选型与查询性能调优:Milvus 实战指南

原创
作者头像
七条猫
发布2026-07-11 10:07:43
发布2026-07-11 10:07:43
20
举报

一、为什么索引选型决定了你系统的天花板

很多团队在引入 Milvus 的时候,往往把精力放在 Embedding 模型选型、数据管道搭建、业务逻辑对接上,而忽略了最底层、也最关键的一环——向量索引选型

但事实是:索引选型一旦错了,后面所有的优化都是在给一个错误的架构打补丁。

我见过太多这样的案例:

  • 某电商团队用 HNSW 索引做了以图搜商品,离线 Recall 98%,线上 P99 延迟 50ms,看起来很美好。结果业务方加了一个"只搜本店铺商品"的标量过滤条件,过滤率 90% 以上,图结构瞬间碎片化,延迟直接飙到 2 秒,Recall 掉到 60% 以下。
  • 某 RAG 知识库项目,数据量 5000 万条,直接用了 IVF_FLAT,内存占用超过 200GB,运维成本爆炸。其实换 IVF_PQ + Refiner,内存能压到 30GB 以内,Recall 还能保持 90% 以上。
  • 还有一个团队,数据量 10 亿级,用了 DiskANN,但 SSD 的 IOPS 没跟上,查询延迟波动极大,最后不得不花大价钱换 NVMe SSD 阵列。

这些坑的共同点是:索引选型没有基于业务场景做系统性评估,而是"看哪个流行用哪个"。

所以,在讲具体索引之前,我先给出一个选型决策的核心框架:

决策维度

关键问题

影响

数据规模

数据量能全部放进内存吗?

决定用内存索引还是磁盘索引

过滤比例

查询时标量过滤会过滤掉多少数据?

决定用图索引还是 IVF 类索引

召回率要求

业务能接受多大的召回率损失?

决定是否需要量化压缩

延迟敏感度

P99 延迟要求多少毫秒?

决定索引参数调优方向

Top-K 大小

每次查询返回多少条结果?

决定 IVF 还是图索引更合适

把这五个问题想清楚,索引选型基本就有了方向。下面逐一展开。


二、Milvus 索引体系全景:从数据结构到量化压缩

Milvus 目前的索引体系已经非常成熟,官方文档将索引拆解为三个核心组件:数据结构(Data Structure)量化压缩(Quantization)精排修正(Refiner)。理解这三层架构,是做好选型的基础。

2.1 两大核心数据结构

Milvus 支持的向量索引数据结构,本质上就两大类:

IVF(倒排文件):通过 K-Means 聚类把向量空间划分为 nlist 个簇,查询时只搜索距离查询向量最近的 nprobe 个簇。它的核心优势是内存效率高、对过滤查询友好、建索引快

图结构(HNSW / DiskANN):基于分层可导航小世界图,查询时从上层粗粒度图逐层导航到下层细粒度图,实现对数级复杂度的搜索。核心优势是查询速度极快、召回率极高

对比维度

IVF 类

HNSW

DiskANN

算法原理

聚类分桶

多层图导航

Vamana 图 + PQ

内存占用

较低

较高(图结构开销大)

低(图存磁盘)

建索引速度

中等

查询速度(无过滤)

快,取决于 nprobe

极快,对数复杂度

快,但有磁盘 I/O 开销

查询速度(高过滤率 >90%)

稳定,簇级粗筛

不稳定,图碎片化严重

相对稳定

召回率

95%+(无量化)/ 70-90%(PQ)

98%+

95%+

适用场景

大规模 + 有过滤 + 内存有限

中小规模 + 无过滤 + 追求极致召回

超大规模 + 内存放不下 + SSD 够快

2.2 量化压缩:用精度换容量

量化压缩是大规模向量检索中不可或缺的一环。Milvus 目前支持三种主要量化方式:

SQ8(标量量化):将每个维度从 float32(4 字节)压缩到 8-bit(1 字节),压缩比 4:1。几何结构保持较好,召回率损失小。适合对召回率要求较高但又想省内存的场景。

PQ(乘积量化):将高维向量切分为多个子空间,每个子空间独立编码。压缩比可以达到 8:1 甚至 64:1。内存省得最多,但召回率损失也最大,通常需要配合 Refiner 使用。

RaBitQ:这是较新加入的一种量化方式,在保持高压缩率的同时,通过随机二值化技术实现了更好的召回率表现。火山引擎的测试数据显示,集成 RaBitQ 后磁盘索引 QPS 可达社区版 5 倍以上。

以 100 万条 128 维 float32 向量为例,不同量化方式的内存占用对比:

索引配置

向量存储

图/簇开销

总内存估算

IVF_FLAT(无压缩)

512 MB

3 MB

~515 MB

IVF_SQ8

128 MB

3 MB

~131 MB

IVF_PQ(8 子量化器)

8 MB

3 MB

~11 MB

HNSW(无压缩)

512 MB

128 MB

~640 MB

HNSW_PQ(8 子量化器)

8 MB

128 MB

~136 MB

HNSW_SQ

128 MB

128 MB

~256 MB

这张表很直观地说明了一个问题:HNSW 的内存开销不仅仅是向量本身,图结构的开销(每个节点 32 条边 × 4 字节 × 100 万 = 128MB)往往被忽视。 在做容量规划时,必须把这部分算进去。

2.3 Refiner:量化时代的"后悔药"

Refiner 是 Milvus 索引架构中一个非常巧妙的设计。它的原理是:量化压缩必然带来精度损失,所以在查询时,系统会多召回 topK × expansion_rate 个候选向量,然后用更高精度(通常是原始 float32 向量)对这些候选重新计算距离,最后返回精排后的 topK 结果。

这意味着:你可以放心地使用 PQ 把内存压到极低,然后通过 Refiner 把召回率拉回来。 代价是查询时会多一些计算开销,但对于大多数场景来说,这个 trade-off 非常值得。


三、场景化选型:不同业务该怎么选

理论讲完了,下面进入实战环节。我根据自己做过的和见过的项目,总结了几种典型业务场景的索引选型策略。

3.1 RAG 知识库检索

典型特征:数据量百万到千万级,通常有租户隔离(标量过滤),过滤率中等(30%-70%),Top-K 较小(5-20),对召回率要求高(直接影响生成质量)。

推荐索引IVF_SQ8 + RefinerHNSW_SQ

理由:RAG 场景的过滤通常是"只搜某个租户的文档",过滤率一般不会超过 85%,HNSW 在这个过滤率下表现尚可。但如果租户数量多、单个租户数据占比小,过滤率可能超过 85%,这时候 IVF 类索引更稳定。

SQ8 量化 + Refiner 的组合,能在内存占用和召回率之间取得很好的平衡。实测 128 维向量,1000 万数据,IVF_SQ8 + Refiner 的内存大约 1.5GB,Recall@10 可以稳定在 92% 以上。

参数建议

  • nlist = 1024 或 2048(百万级数据用 1024,千万级用 2048)
  • nprobe = 8-16(根据延迟预算调整)
  • expansion_rate = 3-5

3.2 以图搜图 / 商品检索

典型特征:数据量千万到亿级,通常无标量过滤或过滤率极低,Top-K 较小(10-50),对延迟极其敏感(用户等着看结果),召回率要求高。

推荐索引HNSW(数据能放内存)或 DiskANN(数据放不进内存)

理由:以图搜图是典型的"纯向量检索 + 低延迟 + 高召回"场景,没有过滤的干扰,HNSW 的图结构优势可以充分发挥。实测 1000 万 512 维向量,HNSW 的 P99 延迟可以控制在 30ms 以内,Recall@10 达到 97% 以上。

但如果数据量到了亿级,512 维向量的 HNSW 索引内存会超过 1TB,这时候 DiskANN 是更现实的选择。DiskANN 把图存在 SSD 上,内存只需要放 PQ 编码后的向量和部分图结构,内存占用可以降到原来的 1/10。

关键提醒:DiskANN 对 SSD 的 IOPS 要求很高。如果用普通 SATA SSD,随机读 IOPS 只有几万,查询延迟会波动很大。建议至少用企业级 NVMe SSD,随机读 IOPS 要能到 50 万以上。

3.3 推荐系统中的向量召回

典型特征:数据量大(亿级),查询并发高,Top-K 较大(100-1000),对延迟敏感但对召回率的容忍度相对较高(后面还有精排模型)。

推荐索引IVF_PQSCANN

理由:推荐系统的向量召回阶段,本质上是在"用粗筛换速度"。IVF_PQ 的高压缩比可以让数据在有限内存中放下更大的候选池,而召回率的损失可以由后续的精排模型来弥补。

SCANN(Scalable Nearest Neighbors)是 Google 提出的各向异性量化索引,在推荐场景下表现优异,Milvus 也已经原生支持。它的特点是:在保持高吞吐的同时,对热门向量的召回率更好——这恰好符合推荐系统"头部内容要召回准、长尾内容可以容忍误差"的特点。

3.4 多模态搜索 / 混合检索

典型特征:同时有文本 Embedding、图像 Embedding、甚至音频 Embedding,需要做多路召回 + 融合排序,通常伴随复杂的标量过滤。

推荐索引多 Collection 分别建索引 + Hybrid Search

Milvus 2.x 支持 Multi-Vector 和 Hybrid Search,可以为不同的模态分别建立 Collection,各自选择最合适的索引,然后在查询时通过 Reciprocal Rank Fusion (RRF) 或加权融合来合并结果。

模态

推荐索引

理由

文本 Embedding(768/1024 维)

IVF_SQ8 + Refiner

维度高、数据量大、通常有过滤

图像 Embedding(512 维)

HNSW

维度适中、追求高召回

稀疏向量(BM25/SPLADE)

SPARSE_INVERTED_INDEX

稀疏向量专用索引


四、查询性能调优:索引选对了只是第一步

索引选型解决了"方向"问题,但真正决定线上表现的是参数调优和架构配置。这部分我按调优的优先级从高到低来讲。

4.1 第一优先级:nprobe / ef_search 调优

这是影响查询延迟和召回率最直接的参数。

IVF 类索引的 nprobe:nprobe 决定了查询时搜索多少个簇。nprobe 越大,召回率越高,但延迟线性增长。实战经验是:从 nprobe = 1 开始测,逐步增加,直到 Recall 达到业务要求的阈值。 大多数场景下,nprobe 在 8-32 之间就能达到 90%+ 的召回率。

HNSW 的 ef_search:ef_search 控制搜索时的候选队列大小。和 nprobe 类似,ef_search 越大召回率越高,但延迟也越大。建议从 ef_search = 64 开始,逐步调整到 128、256,观察 Recall 和延迟的变化曲线。

调优方法论:不要靠猜,要建一个评测集。准备 1000-10000 个查询向量,用暴力搜索的结果作为 Ground Truth,计算不同参数下的 Recall@K。然后画出 Recall-Latency 曲线,找到曲线的"拐点"——那就是最优参数。

4.2 第二优先级:Segment 与分片策略

Milvus 的数据组织方式直接影响查询性能。数据被分成多个 Segment,每个 Segment 独立建索引。Segment 的大小和分布会影响查询的并行度和效率。

关键参数

  • dataCoord.segment.maxSize:控制 Segment 最大大小,默认 512MB。数据量大时可以适当调大到 1024MB,减少 Segment 数量,降低索引构建和查询的开销。
  • rootCoord.dmlChannels:控制写入通道数,影响数据写入的并行度。高并发写入场景可以适当增加。

分片策略:Milvus 的 Collection 可以设置 shard 数量,shard 决定了数据写入和查询的并行度。一般来说,shard 数量和 QueryNode 的数量保持一致或成倍数关系,可以最大化查询并行度。

4.3 第三优先级:mmap 与 lazy load

Milvus 支持 mmap(内存映射文件)机制,允许将部分数据保留在磁盘上,按需加载到内存。这对于数据量大于可用内存的场景非常有用。

使用建议

  • 如果 75% 以上的数据能放进内存,优先用 mmap 管理原始向量数据,让索引结构常驻内存。
  • 如果大部分数据都在磁盘上,DiskANN 是比 mmap 更好的选择,因为 DiskANN 的磁盘访问模式是顺序 + 小范围随机,比 mmap 的页面置换更高效。

Milvus 还支持 lazy load(懒加载),即 Collection 的数据在第一次被查询时才加载到内存。这在多租户场景下非常有用——不需要把所有租户的数据都预加载,而是按需加载。

4.4 第四优先级:QueryNode 资源配置

QueryNode 是 Milvus 中负责执行查询的节点,它的资源配置直接影响查询性能。

CPU:查询是 CPU 密集型操作,尤其是距离计算部分。建议 QueryNode 的 CPU 核数不少于 8 核,高并发场景建议 16 核以上。

内存:必须保证所有需要查询的索引和数据都能加载到内存中(或使用 mmap)。内存不足会导致 OOM 或频繁的 swap,直接导致查询超时。

GPU(可选):如果使用了 GPU_IVF_FLAT 或 GPU_CAGRA 索引,GPU 的显存和计算能力会成为关键瓶颈。GPU 索引在大规模批量查询场景下优势明显,单条查询的优势不大。

4.5 第五优先级:写入与查询的隔离

一个常被忽视的调优点是写入和查询的资源隔离。Milvus 的写入流程(DataNode → Segment flush → IndexNode 建索引 → QueryNode 加载)会消耗 CPU 和 I/O 资源,如果在查询高峰期进行大量写入或索引构建,会直接影响查询延迟。

实战建议

  • 如果写入和查询的负载都很重,考虑将 IndexNode 和 QueryNode 分开部署,避免资源竞争。
  • 使用 Milvus 的资源组(Resource Group)功能,将不同 Collection 的查询负载隔离到不同的 QueryNode 组上。
  • 对于批量导入场景(比如初始化 RAG 知识库),建议在业务低峰期进行,导入完成后再统一建索引和加载。

五、那些官方文档不会告诉你的坑

最后这部分,我分享几个在生产环境中踩过的真实坑,希望能帮你避坑。

5.1 过滤率突变导致 HNSW 性能崩塌

这是最常见的线上故障之一。系统上线初期没有标量过滤,HNSW 跑得很好。后来业务加了过滤条件(比如"只搜最近 7 天的数据"),过滤率突然到了 90% 以上,HNSW 的图结构被大量"屏蔽"节点破坏,搜索退化成接近暴力遍历。

解决方案:如果你的业务过滤率可能超过 85%,从一开始就不要用 HNSW,改用 IVF 类索引。IVF 的簇级粗筛天然适合和标量过滤配合——先通过过滤条件排除不需要的簇,再在剩余簇中做向量检索,性能稳定可预期。

5.2 索引构建时间和内存的隐性成本

很多团队在做容量规划时只算了数据存储的内存,忽略了索引构建过程中的额外内存开销。HNSW 建索引时需要在内存中构建完整的图结构,临时内存可能是最终索引大小的 1.5-2 倍。IVF 建索引时需要做 K-Means 聚类,也需要额外的内存来存储中间结果。

建议:建索引时预留的内存至少是最终索引大小的 2 倍。如果内存不够,可以分批导入数据,分段建索引。

5.3 向量维度的选择不是越大越好

高维向量确实能表达更丰富的语义信息,但维度越高,索引的内存开销越大,距离计算越慢,"维度诅咒"也会导致向量之间的距离区分度下降。

实测数据:

向量维度

100 万条 IVF_SQ8 内存

P99 延迟(nprobe=16)

Recall@10

128 维

~131 MB

~15ms

93.2%

256 维

~259 MB

~28ms

91.8%

512 维

~515 MB

~52ms

89.5%

768 维

~771 MB

~78ms

87.3%

1024 维

~1027 MB

~105ms

85.6%

可以看到,从 128 维到 1024 维,内存线性增长,延迟线性增长,但召回率反而在下降。这是因为维度越高,向量空间中所有点之间的距离趋于均匀,区分度下降。

建议:在选择 Embedding 模型时,不要盲目追求高维度。如果 128 维的模型在你的业务上 Recall 够用,就不要用 768 维的模型。维度的选择应该在"表达能力"和"检索效率"之间找到平衡点。

5.4 不要忽视标量字段的索引

Milvus 对标量字段也支持建立索引(INVERTED、BITMAP、STL_SORT 等)。在混合查询(向量检索 + 标量过滤)场景下,标量字段的索引质量直接影响过滤效率。

建议

  • 字符串类型的过滤字段(如 user_id、tenant_id),使用 INVERTED 索引。
  • 布尔类型或数组类型的过滤字段,使用 BITMAP 索引。
  • 数值类型的范围过滤字段(如 timestamp、price),使用 STL_SORT 索引或 INVERTED 索引。

六、总结与选型速查表

最后,我把全文的核心结论浓缩成一张速查表,方便你在实际项目中快速决策:

场景

数据规模

过滤率

推荐索引

量化方式

关键参数

RAG 知识库

百万-千万

<85%

HNSW / IVF_SQ8

SQ8 + Refiner

ef=128 / nprobe=16

RAG 知识库(高过滤)

百万-千万

85%

IVF_SQ8

SQ8 + Refiner

nlist=2048, nprobe=16

以图搜图

千万级

无/极低

HNSW

无压缩

M=16, ef=256

以图搜图(亿级)

亿级

无/极低

DiskANN

PQ + Refiner

SSD IOPS > 50万

推荐系统召回

亿级

中等

IVF_PQ / SCANN

PQ

nlist=4096, nprobe=32

多模态混合检索

百万-千万

中等

多 Collection 各自建索引

按模态选择

Hybrid Search + RRF

超大规模精确检索

任意

98%

FLAT(暴力搜索)

配合 GPU 加速

最后的最后,三句话总结

  1. 索引选型的本质是在"内存、延迟、召回率"三者之间做 trade-off,没有银弹,只有适合你业务的选择。
  2. 参数调优不要靠猜,建评测集、画 Recall-Latency 曲线、找拐点,这是最科学的方法。
  3. 生产环境最大的变量不是数据量,而是过滤条件的变化。设计架构时,一定要为过滤留余量。

希望这篇文章能帮到正在做向量检索系统选型的你。如果有任何疑问或者想交流实战经验,欢迎在评论区留言。


本文基于 Milvus 2.x 版本撰写,部分特性可能随版本更新有所变化。建议参考 Milvus 官方文档获取最新信息。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么索引选型决定了你系统的天花板
  • 二、Milvus 索引体系全景:从数据结构到量化压缩
    • 2.1 两大核心数据结构
    • 2.2 量化压缩:用精度换容量
    • 2.3 Refiner:量化时代的"后悔药"
  • 三、场景化选型:不同业务该怎么选
    • 3.1 RAG 知识库检索
    • 3.2 以图搜图 / 商品检索
    • 3.3 推荐系统中的向量召回
    • 3.4 多模态搜索 / 混合检索
  • 四、查询性能调优:索引选对了只是第一步
    • 4.1 第一优先级:nprobe / ef_search 调优
    • 4.2 第二优先级:Segment 与分片策略
    • 4.3 第三优先级:mmap 与 lazy load
    • 4.4 第四优先级:QueryNode 资源配置
    • 4.5 第五优先级:写入与查询的隔离
  • 五、那些官方文档不会告诉你的坑
    • 5.1 过滤率突变导致 HNSW 性能崩塌
    • 5.2 索引构建时间和内存的隐性成本
    • 5.3 向量维度的选择不是越大越好
    • 5.4 不要忽视标量字段的索引
  • 六、总结与选型速查表
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档