Skip to content

向量数据库选型实战:Milvus vs Qdrant vs pgvector 的取舍 ​

做 RAG 项目绕不开向量数据库选型。市面上选择一大把——Milvus、Qdrant、pgvector、Weaviate、Chroma……光看官网都说自己最好。这篇复盘我们实际跑了三个主流方案的过程和结论,不讲玄学,只讲实测数据和生产经验。

选型背景 ​

先说项目情况,选型脱离业务就是耍流氓:

维度实际情况
向量规模500 万条,预计增长到 2000 万
维度1024 维(BGE-large-zh)
检索模式混合检索(向量 + BM25 关键词)
并发峰值 50 QPS
延迟要求P99 < 50ms
运维能力小团队,没专职 DBA
已有基础设施PostgreSQL 主库 + Redis

三个候选的技术路线 ​

先理解它们在设计哲学上的根本差异,这决定了各自适合的场景:

┌─────────────────────────────────────────────────────────────────┐
│                    三种技术路线对比                              │
├────────────────┬────────────────┬───────────────────────────────┤
│   Milvus       │   Qdrant       │   pgvector                    │
│   分布式专用    │   单机轻量专用  │   PostgreSQL 扩展              │
├────────────────┼────────────────┼───────────────────────────────┤
│ ┌────────────┐ │ ┌────────────┐ │ ┌──────────────────────────┐  │
│ │ 分布式架构  │ │ │ Rust 单机   │ │ │ 在 PG 里加向量类型        │  │
│ │ 存算分离    │ │ │ 内存索引    │ │ │ 复用 PG 的事务/索引/SQL   │  │
│ │ 多节点集群  │ │ │ WAL 持久化  │ │ │ HNSW + IVFFlat 索引       │  │
│ └────────────┘ │ └────────────┘ │ └──────────────────────────┘  │
│                │                │                               │
│ 强项:         │ 强项:          │ 强项:                        │
│ 海量数据       │ 中小规模极速    │ 与业务数据同库                 │
│ 水平扩展       │ 部署简单        │ 事务一致性                    │
│ 生态丰富       │ 资源占用低      │ 运维成本低                    │
│                │                │                               │
│ 弱项:         │ 弱项:          │ 弱项:                        │
│ 运维复杂       │ 分布式要自己搞  │ 千万级以上性能下降             │
│ 资源占用大     │ 集群版不够成熟  │ 占用 PG 资源                  │
│ 小项目杀鸡用   │ 生态较新        │ 向量检索非原生优化             │
│ 牛刀           │                │                               │
└────────────────┴────────────────┴───────────────────────────────┘

性能压测对比 ​

用同一批数据(500 万条 1024 维向量)做压测,结果如下:

检索延迟(QPS=50,Top-10 召回) ​

指标Milvus (HNSW)Qdrant (HNSW)pgvector (HNSW)
P50 延迟8ms5ms15ms
P95 延迟18ms12ms35ms
P99 延迟28ms20ms52ms
召回率98.2%97.8%96.5%

写入性能 ​

指标MilvusQdrantpgvector
批量写入 QPS8,00012,0003,000
单条写入延迟2ms1ms5ms

资源占用 ​

指标MilvusQdrantpgvector
内存占用6.2 GB3.8 GB5.5 GB
磁盘占用4.1 GB2.9 GB4.8 GB
额外组件etcd + MinIO无无(复用 PG)

数据量增长后的表现 ​

这是最关键的测试——500 万到 2000 万向量的性能变化:

延迟随数据量变化(P99 延迟,QPS=50)

延迟(ms)
  100 │                                              · pgvector
      │                                         ····
   80 │                                    ····
      │                               ····
   60 │                          ····
      │ ·····                ····
   40 │      ·····      ···· · Milvus
      │           ·······
   20 │ · · · · · · · · · · · · · · · Qdrant
      │
    0 └──────┬──────┬──────┬──────┬──────┬──────
          200万   500万  1000万  1500万  2000万
                         数据量

结论:
- Qdrant:数据量增长对延迟影响最小,曲线最平
- Milvus:百万到千万级稳定,分布式优势开始体现
- pgvector:千万级后延迟陡增,HNSW 索引构建也变慢

混合检索的实现差异 ​

我们的需求是向量 + BM25 关键词混合检索,三个方案的实现方式差别很大:

Milvus:2.4+ 支持混合检索 ​

python
from pymilvus import Collection

# Milvus 2.4+ 支持稀疏向量 + 稠密向量混合检索
collection.search(
    data=[dense_vector],           # 稠密向量
    anns_field="dense_vector",
    param={"metric_type": "IP", "params": {"ef": 64}},
    sparse_vectors={sparse_vector}, # 稀疏向量(BM25)
    limit=10
)

优点:内置支持,不用外挂。缺点:稀疏向量检索能力不如专业 BM25 引擎。

Qdrant:原生支持 Payload 过滤 ​

python
from qdrant_client import QdrantClient

client.search(
    collection_name="docs",
    query_vector=embedding,
    query_filter={
        "must": [
            {"key": "category", "match": {"value": "技术"}},
            {"key": "tags", "match": {"any": ["RAG", "向量数据库"]}}
        ]
    },
    limit=10
)

优点:Payload 过滤极快,适合「向量 + 属性」的混合检索。缺点:不是真正的 BM25 全文检索,是属性过滤。

pgvector:SQL 原生联合查询 ​

sql
-- 向量相似度 + 全文检索联合查询,一条 SQL 搞定
SELECT id, content,
       1 - (embedding <=> $1) AS vector_score,
       ts_rank(tsv, plainto_tsquery($2)) AS text_score
FROM documents
WHERE embedding <=> $1 < 0.5        -- 向量相似度过滤
  AND tsv @@ plainto_tsquery($2)    -- 全文匹配
ORDER BY (1 - (embedding <=> $1)) * 0.7 +
         ts_rank(tsv, plainto_tsquery($2)) * 0.3 DESC
LIMIT 10;

优点:向量 + BM25 + 业务条件一条 SQL 搞定,事务一致性强。缺点:大数据量下 SQL 执行计划可能不理想。

最终选型决策 ​

综合评估后的决策矩阵:

评估维度权重MilvusQdrantpgvector
检索性能30%9107
写入性能10%896
运维成本25%5810
混合检索20%8710
扩展性15%1075
加权总分100%7.558.357.85

我们的选择:Qdrant ​

原因:

  1. 500 万数据量 Qdrant 完全 hold 住,延迟表现最好
  2. 部署最简单,单个 Docker 容器就跑起来了,没有 etcd/MinIO 这些额外依赖
  3. 资源占用最低,小团队服务器资源有限
  4. Payload 过滤满足业务需求,虽然不是真 BM25,但配合 ES 做关键词检索够用
  5. 未来 2000 万时如果 Qdrant 扛不住,再迁 Milvus,迁移成本可控

什么情况选另外两个 ​

选 Milvus 的场景:

  • 数据量确定超过 5000 万
  • 需要多副本、高可用集群
  • 有专职运维团队
  • 对检索延迟有极致要求(P99 < 10ms)

选 pgvector 的场景:

  • 数据量在 500 万以内
  • 已经在用 PostgreSQL
  • 向量检索和业务查询强关联(需要 JOIN 业务表)
  • 团队不想引入新组件
  • 项目初期快速验证

生产落地踩的坑 ​

坑 1:HNSW 索引参数没调,默认参数性能差 ​

Qdrant 默认的 HNSW 参数偏保守,建索引后检索延迟比预期高。

解决:hnsw_config 调优,m 和 ef_construct 是核心参数。

python
client.update_collection(
    collection_name="docs",
    hnsw_config={
        "m": 32,              # 每层最大连接数,越大精度越高、内存越多
        "ef_construct": 256,  # 构建时搜索宽度,越大索引质量越好
    }
)
# 检索时 ef 参数
client.search(
    collection_name="docs",
    query_vector=embedding,
    search_params={"hnsw_ef": 128, "exact": False},
    limit=10
)

坑 2:全量重建索引时服务不可用 ​

一开始用「删集合 → 重建 → 导入」的方式更新向量,重建期间服务全挂。

解决:用双集合切换。新建 docs_v2,导入完成后原子切换别名指向。

python
# 创建新集合
client.recreate_collection("docs_v2", ...)
# 导入数据到 docs_v2
# ...
# 切换别名
client.update_collection_aliases(
    actions=[
        DeleteAliasAction("docs"),
        CreateAliasAction("docs", "docs_v2")
    ]
)
# 删除旧集合
client.delete_collection("docs_v1")

坑 3:pgvector 的 HNSW 索引构建慢到怀疑人生 ​

500 万向量建 HNSW 索引花了 6 小时,期间 CPU 100%。

解决:pgvector 适合数据量小的场景,大索引构建用 maintenance_work_mem 调大 + 并行构建。

sql
SET maintenance_work_mem = '2GB';
SET max_parallel_maintenance_workers = 4;
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 128);

坑 4:Milvus 的 etcd 成为单点 ​

Milvus 依赖 etcd 存元数据,etcd 挂了整个集群不可用。

解决:etcd 必须部署集群(至少 3 节点)。这也是小团队不推荐 Milvus 的原因——运维成本高。

复盘总结 ​

向量数据库选型没有「最好」,只有「最合适」。核心判断依据就两条:

  1. 数据量级:500 万以下 pgvector 够用;500 万到 5000 万 Qdrant 最佳;5000 万以上上 Milvus
  2. 运维能力:有 DBA 选 Milvus;小团队选 Qdrant;已有 PG 且不想加组件选 pgvector

技术选型决策树:

                    数据量级?
                       │
           ┌───────────┼───────────┐
           ▼           ▼           ▼
       < 500万     500万~5000万   > 5000万
           │           │           │
           ▼           ▼           ▼
    已有 PG?      Qdrant       Milvus
       │                           │
    ┌──┴──┐                    有专职运维?
    是    否                      │
    │     │                   ┌───┴───┐
    ▼     ▼                   是      否
 pgvector Qdrant              ▼       ▼
                          Milvus   Qdrant
                                   (先顶住)

最后一句:选型不要看官网的 benchmark,要用自己的真实数据跑压测。每家官网都只展示自己擅长的场景,只有你的业务数据不会说谎。

📖本文阅读--次|📊全站访问--次|👥访客--人