摘要:本文围绕「向量数据库选型」展开,系统对比 Milvus、Qdrant、Chroma、pgvector 四款主流方案在架构、性能、功能与一致性上的差异,并给出按场景的选型建议;最后通过一个从 Chroma 原型迁移到 Qdrant 生产环境的完整实战案例,演示迁移步骤与注意事项,助你快速做出合适决策。
1. 引言
随着大模型与 RAG(检索增强生成)应用的普及,向量数据库已成为技术栈中的关键一环。面对 Milvus、Qdrant、Chroma、pgvector 等众多选择,很多开发者会陷入「选择困难」。本文将从架构、功能、性能、适用场景等维度,帮你理清思路,找到最适合自己的方案。
2. 先看本质:向量数据库解决什么问题
在深入对比之前,先明确向量数据库的核心职责:
- 存储:保存高维向量(如 768 维、1536 维的 Embedding)及其关联的元数据。
- 检索:通过近似最近邻(ANN)算法,在海量向量中快速找到「语义最相似」的 Top-K 结果。
- 过滤:在向量检索的同时,结合标量字段(如时间、类别、权限)进行混合过滤。
理解这一点后,我们再看各产品的定位差异。
3. 四款主流向量数据库速览
| 产品 | 定位 | 部署形态 | 核心优势 | 典型场景 |
|---|---|---|---|---|
| Milvus | 分布式向量数据库 | 独立集群(可云原生) | 超大规模、高并发、功能全 | 生产级大规模 RAG、推荐、搜索 |
| Qdrant | 高性能向量搜索引擎 | 独立服务(单机/集群) | 性能出色、Rust 编写、过滤能力强 | 中等规模生产、实时检索 |
| Chroma | 轻量级嵌入式向量库 | 进程内/本地 | 极简、上手快、与 LangChain 集成好 | 原型验证、教学、小规模应用 |
| pgvector | PostgreSQL 扩展 | 嵌入现有 PG 实例 | 复用 PG 生态、事务一致、运维简单 | 已有 PG 业务、中小规模、需强一致性 |
4. 深度对比:关键维度逐个看
4.1 架构与部署复杂度
- Milvus:采用存算分离架构,由 Coordinator、Proxy、Query Node、Data Node 等组件构成,依赖 etcd、MinIO/S3、Pulsar/Kafka。功能强大,但部署和运维成本最高,适合有专门基础设施团队的场景。
- Qdrant:单一二进制文件即可运行,支持单机与分布式模式。Rust 实现,资源占用相对可控,部署比 Milvus 简单很多。
- Chroma:可嵌入 Python 进程,也可作为独立服务运行。零配置起步,几行代码即可完成「写入-检索」闭环。
- pgvector:作为 PostgreSQL 扩展安装,无需额外引入新组件,完全复用现有数据库的备份、监控、权限体系。
4.2 性能与扩展性
- Milvus:专为海量数据设计,支持百亿级向量规模,通过分片与负载均衡实现水平扩展,高并发下表现稳定。
- Qdrant:在单机性能上非常出色,支持多种索引类型(HNSW、IVF),并提供精准的过滤与负载均衡能力,适合对延迟敏感的场景。
- Chroma:面向中小规模数据,性能足够满足原型与轻量应用,但缺乏分布式扩展能力。
- pgvector:借助 PG 的成熟能力,支持 HNSW 与 IVFFlat 索引。数据量在千万级以内时表现良好,但超大规模下扩展性受限。
4.3 性能基准测试参考
为了更直观地对比四款产品在不同数据规模下的表现,这里给出一个基准测试参考。测试使用 1536 维 Embedding、HNSW 索引、余弦相似度,单机部署(Milvus 为单机 Standalone 模式),并发 50 线程,查询 Top-10。数据为公开社区基准与官方文档数据的综合参考值,实际结果会因硬件、数据分布、索引参数而异,仅用于选型时的量级判断。
| 数据量 | 指标 | Milvus | Qdrant | Chroma | pgvector |
|---|---|---|---|---|---|
| 百万级(100 万) | 查询延迟(P99) | 8--15 ms | 5--10 ms | 10--25 ms | 15--40 ms |
| 百万级(100 万) | QPS | 800--1500 | 1200--2000 | 300--600 | 200--500 |
| 百万级(100 万) | 内存占用 | 约 2--4 GB | 约 1--2 GB | 约 0.5--1 GB | 约 1--2 GB(含 PG) |
| 千万级(1000 万) | 查询延迟(P99) | 15--30 ms | 12--25 ms | 50--150 ms | 60--200 ms |
| 千万级(1000 万) | QPS | 500--1000 | 800--1500 | 80--200 | 50--150 |
| 千万级(1000 万) | 内存占用 | 约 8--16 GB | 约 6--12 GB | 约 4--8 GB | 约 8--16 GB(含 PG) |
| 亿级(1 亿) | 查询延迟(P99) | 30--60 ms | 40--80 ms | 不适用(无分布式扩展) | 不适用(扩展性受限) |
| 亿级(1 亿) | QPS | 300--800 | 400--900 | 不适用 | 不适用 |
| 亿级(1 亿) | 内存占用 | 约 32--64 GB | 约 24--48 GB | 不适用 | 不适用 |
测试环境与版本信息:
- 硬件:8 核 CPU / 32 GB 内存 / NVMe SSD。
- Milvus:v2.4.x,Standalone 模式,HNSW(M=16,efConstruction=200)。
- Qdrant:v1.9.x,单节点,HNSW(M=16,efConstruction=200)。
- Chroma:v0.5.x,PersistentClient 本地模式。
- pgvector:v0.7.x,PostgreSQL 16,HNSW(m=16,ef_construction=200)。
说明:Chroma 与 pgvector 在亿级数据下通常不作为生产首选------前者缺乏分布式扩展能力,后者在超大规模下扩展性受限,因此表中标注为「不适用」。若你的场景达到亿级,建议优先评估 Milvus 或 Qdrant 集群方案。
4.4 功能特性
| 功能 | Milvus | Qdrant | Chroma | pgvector |
|---|---|---|---|---|
| 向量索引类型 | HNSW、IVF、DiskANN 等 | HNSW、IVF | HNSW | HNSW、IVFFlat |
| 标量过滤 | 强(支持复杂表达式) | 强(Payload 过滤) | 基础 | 强(SQL 级过滤) |
| 多租户/权限 | 支持 | 支持 | 有限 | 支持(PG 权限) |
| 数据持久化 | 支持(对象存储) | 支持(本地/云盘) | 支持(本地) | 支持(PG 存储) |
| 生态集成 | LangChain、LlamaIndex、Spark 等 | LangChain、LlamaIndex 等 | LangChain、LlamaIndex 等 | LangChain、Django、SQLAlchemy 等 |
4.5 数据一致性
- pgvector:天然继承 PostgreSQL 的 ACID 事务特性,写入即可见,适合对数据一致性要求极高的业务。
- Milvus / Qdrant:提供最终一致性,写入后存在短暂延迟,但通常能满足检索场景需求。
- Chroma:单机模式下一致性较好,但缺乏分布式事务保障。
5. 选型决策:按场景对号入座
场景一:快速原型 / 学习 / 个人项目
推荐:Chroma
如果你只是想快速验证 RAG 思路、跑通 Demo,或数据量在百万级以内,Chroma 是最省心的选择。它与 LangChain 深度集成,几乎零学习成本。
python
import chromadb
client = chromadb.Client()
collection = client.create_collection("demo")
collection.add(
documents=["这是第一条文档", "这是第二条文档"],
ids=["doc1", "doc2"]
)
results = collection.query(query_texts=["查询内容"], n_results=2)
print(results)
场景二:已有 PostgreSQL 业务,数据量中等
推荐:pgvector
如果你的业务已经跑在 PostgreSQL 上,且向量数据量在千万级以内,pgvector 是最平滑的升级路径。无需引入新组件,直接复用现有运维体系。
sql
-- 创建扩展
CREATE EXTENSION vector;
-- 建表
CREATE TABLE items (
id bigserial PRIMARY KEY,
content text,
embedding vector(1536)
);
-- 创建 HNSW 索引
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
-- 相似度检索
SELECT id, content, 1 - (embedding <=> '[...]') AS similarity
FROM items
ORDER BY embedding <=> '[...]'
LIMIT 5;
场景三:生产级大规模 RAG / 搜索
推荐:Milvus
当数据量达到亿级以上、需要高并发与水平扩展时,Milvus 是更稳妥的选择。它提供了完整的分布式能力与丰富的生态工具。
python
from pymilvus import connections, Collection, CollectionSchema, FieldSchema, DataType
connections.connect(host="localhost", port="19530")
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536)
]
schema = CollectionSchema(fields, description="RAG collection")
collection = Collection("rag_docs", schema)
collection.create_index("embedding", {"index_type": "HNSW", "metric_type": "COSINE"})
场景四:中等规模、追求性能与过滤能力
推荐:Qdrant
如果你需要比 Chroma 更强的性能与过滤能力,又不想承担 Milvus 的运维复杂度,Qdrant 是很好的平衡点。
python
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
client = QdrantClient(host="localhost", port=6333)
client.recreate_collection(
collection_name="docs",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
)
client.upsert(
collection_name="docs",
points=[PointStruct(id=1, vector=[0.1] * 1536, payload={"category": "tech"})]
)
6. 实战案例:从原型到生产
前面我们按场景给出了选型建议,但很多团队的真实路径是:先用 Chroma 快速验证 RAG 思路,等业务跑通、数据量上来后,再迁移到 Qdrant 这类更适合生产环境的方案。下面用一个完整案例,演示这条「从原型到生产」的迁移之路。
6.1 迁移背景
假设我们做了一个内部知识库问答系统,最初用 Chroma 存储文档向量,跑通了 Demo。随着业务推广,数据量增长到千万级,并出现了以下痛点:
- 并发能力不足:Chroma 单机模式在高并发查询下延迟明显上升。
- 过滤能力弱:需要按部门、权限、时间等标量字段做精细过滤,Chroma 支持有限。
- 运维与监控缺失:缺少集群部署、健康检查、指标监控等生产级能力。
于是我们决定迁移到 Qdrant,它性能出色、过滤能力强,且部署比 Milvus 简单,是中等规模生产环境的理想选择。
6.2 迁移步骤总览
#mermaid-svg-hZC6H7Vm8dQZrh3L{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hZC6H7Vm8dQZrh3L .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hZC6H7Vm8dQZrh3L .error-icon{fill:#552222;}#mermaid-svg-hZC6H7Vm8dQZrh3L .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hZC6H7Vm8dQZrh3L .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hZC6H7Vm8dQZrh3L .marker.cross{stroke:#333333;}#mermaid-svg-hZC6H7Vm8dQZrh3L svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hZC6H7Vm8dQZrh3L p{margin:0;}#mermaid-svg-hZC6H7Vm8dQZrh3L .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hZC6H7Vm8dQZrh3L .cluster-label text{fill:#333;}#mermaid-svg-hZC6H7Vm8dQZrh3L .cluster-label span{color:#333;}#mermaid-svg-hZC6H7Vm8dQZrh3L .cluster-label span p{background-color:transparent;}#mermaid-svg-hZC6H7Vm8dQZrh3L .label text,#mermaid-svg-hZC6H7Vm8dQZrh3L span{fill:#333;color:#333;}#mermaid-svg-hZC6H7Vm8dQZrh3L .node rect,#mermaid-svg-hZC6H7Vm8dQZrh3L .node circle,#mermaid-svg-hZC6H7Vm8dQZrh3L .node ellipse,#mermaid-svg-hZC6H7Vm8dQZrh3L .node polygon,#mermaid-svg-hZC6H7Vm8dQZrh3L .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hZC6H7Vm8dQZrh3L .rough-node .label text,#mermaid-svg-hZC6H7Vm8dQZrh3L .node .label text,#mermaid-svg-hZC6H7Vm8dQZrh3L .image-shape .label,#mermaid-svg-hZC6H7Vm8dQZrh3L .icon-shape .label{text-anchor:middle;}#mermaid-svg-hZC6H7Vm8dQZrh3L .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hZC6H7Vm8dQZrh3L .rough-node .label,#mermaid-svg-hZC6H7Vm8dQZrh3L .node .label,#mermaid-svg-hZC6H7Vm8dQZrh3L .image-shape .label,#mermaid-svg-hZC6H7Vm8dQZrh3L .icon-shape .label{text-align:center;}#mermaid-svg-hZC6H7Vm8dQZrh3L .node.clickable{cursor:pointer;}#mermaid-svg-hZC6H7Vm8dQZrh3L .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hZC6H7Vm8dQZrh3L .arrowheadPath{fill:#333333;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hZC6H7Vm8dQZrh3L .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hZC6H7Vm8dQZrh3L .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hZC6H7Vm8dQZrh3L .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hZC6H7Vm8dQZrh3L .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hZC6H7Vm8dQZrh3L .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hZC6H7Vm8dQZrh3L .cluster text{fill:#333;}#mermaid-svg-hZC6H7Vm8dQZrh3L .cluster span{color:#333;}#mermaid-svg-hZC6H7Vm8dQZrh3L div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hZC6H7Vm8dQZrh3L .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hZC6H7Vm8dQZrh3L rect.text{fill:none;stroke-width:0;}#mermaid-svg-hZC6H7Vm8dQZrh3L .icon-shape,#mermaid-svg-hZC6H7Vm8dQZrh3L .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hZC6H7Vm8dQZrh3L .icon-shape p,#mermaid-svg-hZC6H7Vm8dQZrh3L .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hZC6H7Vm8dQZrh3L .icon-shape .label rect,#mermaid-svg-hZC6H7Vm8dQZrh3L .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hZC6H7Vm8dQZrh3L .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hZC6H7Vm8dQZrh3L .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hZC6H7Vm8dQZrh3L :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 导出 Chroma 数据
启动 Qdrant 服务
创建 Collection 与索引
编写迁移脚本
全量数据导入
双写与校验
切换读流量
下线 Chroma
整个迁移分为六个阶段,下面逐一展开。
6.3 第一步:导出 Chroma 数据
Chroma 的数据存储在本地目录中,我们可以通过其 Python API 读取全部数据并导出为 JSON 文件,作为迁移的中间载体。
python
import chromadb
import json
client = chromadb.PersistentClient(path="./chroma_data")
collection = client.get_collection("knowledge_base")
# 读取全部数据(注意:get 默认有上限,需分批拉取)
all_data = collection.get(include=["documents", "metadatas", "embeddings"])
records = []
for i in range(len(all_data["ids"])):
records.append({
"id": all_data["ids"][i],
"document": all_data["documents"][i],
"metadata": all_data["metadatas"][i],
"embedding": all_data["embeddings"][i],
})
with open("chroma_export.json", "w", encoding="utf-8") as f:
json.dump(records, f, ensure_ascii=False)
print(f"已导出 {len(records)} 条记录")
注意 :Chroma 的
get方法默认有返回条数上限,数据量大时务必使用limit与offset参数分批拉取,避免数据丢失。
6.4 第二步:启动 Qdrant 并创建 Collection
Qdrant 支持 Docker 一键部署,这里以单机模式为例:
bash
docker run -d \
--name qdrant \
-p 6333:6333 \
-p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage \
qdrant/qdrant
启动后,用 Python 客户端创建 Collection。注意向量维度必须与 Chroma 中导出的 Embedding 维度一致(本例为 1536 维)。
python
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
client = QdrantClient(host="localhost", port=6333)
client.recreate_collection(
collection_name="knowledge_base",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)
print("Collection 创建成功")
6.5 第三步:编写迁移脚本并全量导入
读取导出的 JSON 文件,逐批写入 Qdrant。建议使用 upsert 分批提交,并开启 wait=True 确保写入落盘。
python
import json
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct
client = QdrantClient(host="localhost", port=6333)
with open("chroma_export.json", "r", encoding="utf-8") as f:
records = json.load(f)
BATCH_SIZE = 500
for i in range(0, len(records), BATCH_SIZE):
batch = records[i : i + BATCH_SIZE]
points = [
PointStruct(
id=hash(rec["id"]) % (2**63), # 将字符串 ID 映射为整数 ID
vector=rec["embedding"],
payload={
"document": rec["document"],
**rec["metadata"],
},
)
for rec in batch
]
client.upsert(
collection_name="knowledge_base",
points=points,
wait=True,
)
print(f"已导入 {i + len(batch)} / {len(records)} 条")
print("全量导入完成")
注意:Qdrant 的 Point ID 必须是 64 位无符号整数。如果 Chroma 中使用的是字符串 ID,需要设计稳定的哈希映射,避免迁移后 ID 冲突或无法对应回原业务数据。
6.6 第四步:双写与数据校验
切换流量前,建议先让新旧两套系统并行运行一段时间,并做一致性校验。
python
from qdrant_client import QdrantClient
import chromadb
qdrant = QdrantClient(host="localhost", port=6333)
chroma_client = chromadb.PersistentClient(path="./chroma_data")
chroma_col = chroma_client.get_collection("knowledge_base")
# 随机抽取若干条,对比检索结果
test_queries = ["如何配置权限", "数据库连接超时怎么办", "日志清理策略"]
for q in test_queries:
qdrant_res = qdrant.query(
collection_name="knowledge_base",
query_text=q,
limit=3,
)
chroma_res = chroma_col.query(query_texts=[q], n_results=3)
print(f"查询:{q}")
print(f" Qdrant Top1: {qdrant_res.points[0].payload['document'][:30]}")
print(f" Chroma Top1: {chroma_res['documents'][0][0][:30]}")
校验通过后,将写入逻辑改为「双写」:新数据同时写入 Chroma 与 Qdrant,读流量逐步切到 Qdrant。
6.7 第五步:切换流量并下线 Chroma
确认 Qdrant 检索结果与 Chroma 一致后,按以下顺序完成切换:
- 切读流量:将查询接口全部指向 Qdrant,观察一段时间,确认无异常。
- 停双写:确认稳定后,停止向 Chroma 写入,仅保留 Qdrant。
- 备份归档:对 Chroma 数据目录做一次完整备份,保留一段时间以备回滚。
- 下线服务:确认无误后,停止并移除 Chroma 相关进程与存储。
6.8 迁移注意事项
- 向量维度一致性:迁移前务必确认两边 Embedding 模型一致、维度相同,否则检索结果会失真。
- ID 映射策略:提前设计好字符串 ID 到整数 ID 的映射规则,避免迁移后无法关联原业务数据。
- 分批导入与断点续传:数据量大时,建议记录已导入的批次,失败时可从断点继续,避免全量重跑。
- 先校验再切换:不要一次性切换全部流量,先灰度、再全量,降低风险。
- 保留回滚能力:下线 Chroma 前保留完整备份,给线上留一条退路。
6. 决策流程图
#mermaid-svg-FDIW71cs3zQdm2NJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FDIW71cs3zQdm2NJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FDIW71cs3zQdm2NJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FDIW71cs3zQdm2NJ .error-icon{fill:#552222;}#mermaid-svg-FDIW71cs3zQdm2NJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FDIW71cs3zQdm2NJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FDIW71cs3zQdm2NJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FDIW71cs3zQdm2NJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FDIW71cs3zQdm2NJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FDIW71cs3zQdm2NJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FDIW71cs3zQdm2NJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FDIW71cs3zQdm2NJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FDIW71cs3zQdm2NJ .marker.cross{stroke:#333333;}#mermaid-svg-FDIW71cs3zQdm2NJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FDIW71cs3zQdm2NJ p{margin:0;}#mermaid-svg-FDIW71cs3zQdm2NJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FDIW71cs3zQdm2NJ .cluster-label text{fill:#333;}#mermaid-svg-FDIW71cs3zQdm2NJ .cluster-label span{color:#333;}#mermaid-svg-FDIW71cs3zQdm2NJ .cluster-label span p{background-color:transparent;}#mermaid-svg-FDIW71cs3zQdm2NJ .label text,#mermaid-svg-FDIW71cs3zQdm2NJ span{fill:#333;color:#333;}#mermaid-svg-FDIW71cs3zQdm2NJ .node rect,#mermaid-svg-FDIW71cs3zQdm2NJ .node circle,#mermaid-svg-FDIW71cs3zQdm2NJ .node ellipse,#mermaid-svg-FDIW71cs3zQdm2NJ .node polygon,#mermaid-svg-FDIW71cs3zQdm2NJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FDIW71cs3zQdm2NJ .rough-node .label text,#mermaid-svg-FDIW71cs3zQdm2NJ .node .label text,#mermaid-svg-FDIW71cs3zQdm2NJ .image-shape .label,#mermaid-svg-FDIW71cs3zQdm2NJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-FDIW71cs3zQdm2NJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FDIW71cs3zQdm2NJ .rough-node .label,#mermaid-svg-FDIW71cs3zQdm2NJ .node .label,#mermaid-svg-FDIW71cs3zQdm2NJ .image-shape .label,#mermaid-svg-FDIW71cs3zQdm2NJ .icon-shape .label{text-align:center;}#mermaid-svg-FDIW71cs3zQdm2NJ .node.clickable{cursor:pointer;}#mermaid-svg-FDIW71cs3zQdm2NJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FDIW71cs3zQdm2NJ .arrowheadPath{fill:#333333;}#mermaid-svg-FDIW71cs3zQdm2NJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FDIW71cs3zQdm2NJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FDIW71cs3zQdm2NJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FDIW71cs3zQdm2NJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FDIW71cs3zQdm2NJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FDIW71cs3zQdm2NJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FDIW71cs3zQdm2NJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FDIW71cs3zQdm2NJ .cluster text{fill:#333;}#mermaid-svg-FDIW71cs3zQdm2NJ .cluster span{color:#333;}#mermaid-svg-FDIW71cs3zQdm2NJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FDIW71cs3zQdm2NJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FDIW71cs3zQdm2NJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-FDIW71cs3zQdm2NJ .icon-shape,#mermaid-svg-FDIW71cs3zQdm2NJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FDIW71cs3zQdm2NJ .icon-shape p,#mermaid-svg-FDIW71cs3zQdm2NJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FDIW71cs3zQdm2NJ .icon-shape .label rect,#mermaid-svg-FDIW71cs3zQdm2NJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FDIW71cs3zQdm2NJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FDIW71cs3zQdm2NJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FDIW71cs3zQdm2NJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
是
否
否
是
是
否
否
是
否
开始选型
已有 PostgreSQL 业务?
数据量 < 千万级?
pgvector
Milvus
需要生产级大规模?
需要强过滤与高性能?
Qdrant
快速原型/学习?
Chroma
7. 总结与建议
- Chroma:适合快速验证与轻量应用,上手最快。
- pgvector:适合已有 PG 生态、数据量中等、重视事务一致性的场景。
- Qdrant:适合中等规模生产环境,性能与过滤能力均衡。
- Milvus:适合大规模、高并发、需要水平扩展的生产级系统。
选型没有「最好」,只有「最合适」。建议先明确自己的数据规模、运维能力与业务需求,再结合本文的对比做出决策。如果条件允许,可以用真实数据做一轮基准测试,用数据说话。