AI Agent开发实战⑬|向量数据库选型实战:Chroma vs Milvus vs Qdrant百万级数据性能对比

选向量数据库和选房子一样,没有最好的,只有最合适的。小数据量用Chroma够用且简单,但到了百万级数据,选错数据库能让你的检索从50ms变成5秒。本文实测三款主流向量库在不同规模下的表现。

一、向量数据库的核心能力

向量数据库要解决三个问题:

写入速度:向量入库有多快?
检索速度:Top-K查询需要多久?
扩展能力:数据量增长后性能衰减多少?

一个真实踩坑:

项目初期:1万条向量,Chroma检索20ms,够用
项目中期:50万条向量,Chroma检索800ms,开始慢
项目后期:200万条向量,Chroma检索3.5秒,用户投诉

迁移到Milvus后:200万条检索稳定在50ms
迁移成本:3天重构 + 1周数据迁移

教训:选型时就要考虑未来规模,避免中途迁移。

二、三款主流向量库对比

2.1 基本特性

特性 Chroma Milvus Qdrant
定位 轻量级、嵌入式 企业级、分布式 云原生、高性能
部署复杂度 ⭐⭐⭐⭐ ⭐⭐⭐
最大数据量 100万级 10亿级 10亿级
持久化 SQLite/ClickHouse 独立存储 RocksDB
分布式
云服务 Zilliz Cloud Qdrant Cloud
开源协议 Apache 2.0 Apache 2.0 Apache 2.0

2.2 功能对比

功能 Chroma Milvus Qdrant
向量索引 HNSW HNSW/IVF/DiskANN HNSW
元数据过滤 ✅ 基础 ✅ 强大 ✅ 强大
混合检索
量化压缩 ✅ PQ/SQ ✅ 标量量化
多向量查询
实时更新
批量导入 ✅ 高效 ✅ 高效

三、性能实测

3.1 测试环境

测试配置:
- 硬件:Intel i7-12700, 32GB RAM, 1TB NVMe SSD
- 向量维度:1024(BGE-large-zh标准输出)
- 索引类型:HNSW(三款都支持)
- 测试规模:10/ 50/ 100/ 500万

测试任务:
1. 批量写入速度
2. 单查询延迟(P50/P95/P99)
3. 并发查询吞吐量
4. 内存占用

3.2 写入性能

批量写入100万向量(batch_size=1000):

数据库 写入耗时 吞吐量(向量/秒) 内存峰值
Chroma 342秒 2,924 8.2GB
Milvus 127秒 7,874 12.1GB
Qdrant 156秒 6,410 9.8GB

Milvus写入最快,主要因为批量插入优化做得好。

3.3 查询性能

单查询延迟(Top-10,P95)

数据量 Chroma Milvus Qdrant
10万 15ms 12ms 11ms
50万 78ms 28ms 32ms
100万 186ms 41ms 48ms
500万 1,247ms 89ms 102ms

关键发现

  • 10万级:三款差距不大
  • 100万级:Milvus比Chroma快4.5倍
  • 500万级:Milvus比Chroma快14倍

Qdrant性能与Milvus接近,两者在百万级数据下都保持<100ms的P95延迟。

3.4 并发性能

并发查询吞吐量(100万向量,100并发)

数据库 QPS P95延迟 P99延迟
Chroma 156 892ms 1.2s
Milvus 1,247 58ms 89ms
Qdrant 1,102 62ms 95ms

Milvus并发能力最强,适合高QPS场景。

3.5 内存占用

数据量 Chroma Milvus Qdrant
10万 1.2GB 1.8GB 1.5GB
100万 8.2GB 11.3GB 9.7GB
500万 38GB 32GB 29GB

Qdrant内存效率最高,得益于Rust实现和高效的内存管理。

3.6 元数据过滤性能

# 测试场景:100万向量,带元数据过滤
query = "研发投入"
filter = {"domain": "财务", "year": 2023}

# 结果
{
    "Chroma": "234ms(过滤能力有限,先检索后过滤)",
    "Milvus": "43ms(索引内过滤)",
    "Qdrant": "51ms(索引内过滤)"
}

Milvus和Qdrant支持索引内过滤,大幅提升带条件查询的速度。

四、不同规模下的选型建议

4.1 小规模(<10万向量)

# 推荐方案:Chroma
# 理由:
# 1. 部署最简单,pip install chromadb 即可
# 2. 嵌入式运行,无需独立服务
# 3. 性能够用,检索<20ms
# 4. 开发效率最高

# 示例代码
import chromadb
from chromadb.config import Settings

client = chromadb.Client(Settings(
    chroma_db_impl="duckdb+parquet",
    persist_directory="./chroma_db"
))

collection = client.create_collection("documents")
collection.add(
    embeddings=embeddings,
    documents=documents,
    metadatas=metadatas,
    ids=ids
)

results = collection.query(
    query_embeddings=query_vec,
    n_results=10
)

4.2 中等规模(10万-100万向量)

# 推荐方案:Qdrant(Docker单机部署)
# 理由:
# 1. 部署简单(docker run一条命令)
# 2. 性能优秀(P95<50ms)
# 3. 内存效率高
# 4. 支持元数据过滤

# 部署命令
# docker run -p 6333:6333 qdrant/qdrant

from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams

client = QdrantClient(host="localhost", port=6333)

client.create_collection(
    collection_name="documents",
    vectors_config=VectorParams(size=1024, distance=Distance.COSINE)
)

# 批量插入
client.upsert(
    collection_name="documents",
    points=points  # [{"id": 1, "vector": [...], "payload": {...}}, ...]
)

# 查询
results = client.search(
    collection_name="documents",
    query_vector=query_vec,
    limit=10,
    query_filter={"must": [{"key": "domain", "match": {"value": "财务"}}]}
)

4.3 大规模(100万-1000万向量)

# 推荐方案:Milvus(集群部署)
# 理由:
# 1. 写入性能最强
# 2. 并发能力最强
# 3. 支持分布式扩展
# 4. 企业级功能完善

# 部署:Docker Compose
# wget https://github.com/milvus-io/milvus/releases/download/v2.3.0/milvus-standalone-docker-compose.yml
# docker-compose -f milvus-standalone-docker-compose.yml up -d

from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType

connections.connect("default", host="localhost", port="19530")

# 定义schema
fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
    FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1024)
]
schema = CollectionSchema(fields, "document collection")

# 创建collection
collection = Collection("documents", schema)

# 创建索引(HNSW)
index_params = {
    "metric_type": "COSINE",
    "index_type": "HNSW",
    "params": {"M": 16, "efConstruction": 256}
}
collection.create_index("embedding", index_params)

# 插入数据
collection.insert([ids, embeddings])

# 搜索
search_params = {"metric_type": "COSINE", "params": {"ef": 64}}
results = collection.search(
    data=[query_vec],
    anns_field="embedding",
    param=search_params,
    limit=10
)

4.4 超大规模(>1000万向量)

# 推荐方案:Milvus集群 + 量化
# 理由:
# 1. 唯一支持10亿级开源方案
# 2. PQ/SQ量化减少内存占用
# 3. 分片+副本支持高可用

# 量化配置(减少75%内存)
quantization_params = {
    "nlist": 1024,
    "m": 32,  # PQ子空间数
    "nbits": 8
}

collection.create_index(
    "embedding",
    {
        "index_type": "IVF_PQ",
        "metric_type": "COSINE",
        "params": quantization_params
    }
)

五、选型决策树

第一步:数据规模评估
    │
    ├── <10万向量
    │   → 【Chroma】
    │   理由:部署最简单,性能够用
    │
    ├── 10万-100万
    │   → 【Qdrant】或【Milvus单机】
    │   理由:性能好、部署可控
    │
    ├── 100万-1000万
    │   → 【Milvus集群】
    │   理由:性能最强、可扩展
    │
    └── >1000万
        → 【Milvus集群 + 量化】或云服务
        理由:需要分布式能力

第二步:部署约束
    │
    ├── 开发环境/快速验证
    │   → Chroma(嵌入式)
    │
    ├── 生产环境、有运维能力
    │   → Milvus/Qdrant(Docker)
    │
    └── 无运维能力、追求稳定
        → 云服务(Zilliz Cloud / Qdrant Cloud)

六、迁移成本对比

如果后期需要迁移,各数据库的迁移成本:

迁移路径 复杂度 耗时(100万向量) 主要工作
Chroma → Qdrant 2小时 数据导出+格式转换
Chroma → Milvus 3小时 数据导出+格式转换
Qdrant → Milvus 1小时 API适配
Milvus → Qdrant 1小时 API适配

建议:初期选型时就要考虑未来规模,避免Chroma到百万级再迁移。

七、总结

场景 推荐方案 理由
原型验证/开发阶段 Chroma 最简单,零配置
<10万向量 Chroma 够用,性能可接受
10-100万向量 Qdrant 性能好、部署简单
100-1000万向量 Milvus 性能最强
>1000万向量 Milvus集群 唯一开源选择

下篇预告:「检索策略深度对比:向量检索 vs BM25 vs 混合检索的实测选型」——同样的数据、不同的检索策略,效果能差多少?


需要完整测试代码和迁移脚本的同学,可以看我主页的付费资源专栏。

有问题欢迎评论区留言,大家一起讨论!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐