向量数据库选型:pgvector / Qdrant / LanceDB / Milvus

起因

RAG 场景需要向量检索:

  • embed 文档 chunk → 存向量
  • query 时 embed query → 找最近的 K 个 chunk
  • chunk 喂 LLM 做答

向量 DB 选择多:pgvector / Qdrant / Weaviate / Milvus / Pinecone /
LanceDB / Chroma。痛苦。

下面对比 + 我的选型建议。

候选

pgvector(Postgres 扩展)

CREATE EXTENSION vector;
CREATE TABLE chunks (
    id BIGSERIAL PRIMARY KEY,
    content TEXT,
    embedding vector(1536)
);

CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops);

-- 查
SELECT content
FROM chunks
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 10;
  • 已有 PG → 0 引入新组件
  • 同事务支持 metadata + 向量
  • 性能:HNSW index 几百万 vector OK,千万级别仍可(精度 vs 速度调)

Qdrant(Rust)

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

client = QdrantClient('localhost', port=6333)
client.recreate_collection('docs',
    vectors_config=VectorParams(size=1536, distance=Distance.COSINE))

client.upsert('docs', points=[
    PointStruct(id=1, vector=[0.1]*1536, payload={'text': '...'}),
])

results = client.search('docs', query_vector=[0.1]*1536, limit=10,
    query_filter={'must': [{'key': 'lang', 'match': {'value': 'zh'}}]})
  • Rust 写,单机性能强
  • payload 支持 filter(带 metadata 过滤)
  • 部署简单(docker run 一行)

LanceDB

import lancedb

db = lancedb.connect('./lance_data')
tbl = db.create_table('docs', data=[
    {'vector': [0.1]*1536, 'text': '...'},
])
results = tbl.search([0.1]*1536).limit(10).to_pandas()
  • 嵌入式(无 server,类似 SQLite)
  • 单 binary,无依赖
  • 数据存 Lance 列式格式
  • 适合 < 1 亿 vector / 不要分布式

Milvus

  • 老牌(2019+)
  • 真正分布式 + 集群(cloud-native)
  • 适合数十亿 vector / 高 QPS
  • 部署复杂

Chroma / Weaviate

  • Chroma:embedded / server,开发体验最好
  • Weaviate:Go 写,schema + GraphQL
  • 我用得少

性能对比

10M vectors / 1536d / 测试:

DB 索引时间 P50 query RAM
pgvector (HNSW) 30 min 12 ms 25 GB
Qdrant 15 min 5 ms 18 GB
LanceDB 10 min 8 ms 8 GB (disk-based)
Milvus 12 min 4 ms 20 GB

Qdrant / Milvus 在 raw 性能最强。pgvector 略慢但 ergonomics 最好。

选型建议

场景 推荐
已有 PG 应用 + < 1000w vector pgvector
独立向量服务 + 中等规模(千万级) Qdrant
嵌入应用 / 单机 / 不想跑 server LanceDB
数十亿规模 / 集群 Milvus
全托管不想运维 Pinecone(贵)/ Qdrant Cloud / Pinecone serverless

我个人项目 100% pgvector:

  • DB 已经在
  • transaction 跟其它 data 一致
  • 不想多维护一个组件
  • 性能够(< 100w vector)

pgvector 详细 + 优化

-- HNSW index(更适合高维)
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

-- 查询时 ef_search 控制精度/速度
SET hnsw.ef_search = 100;

-- 半精度向量(节省一半空间,损失小)
ALTER TABLE chunks ALTER COLUMN embedding TYPE halfvec(1536);
CREATE INDEX ON chunks USING hnsw (embedding halfvec_cosine_ops);

halfvec(pgvector 0.7+)省内存 50%,精度损失 1-2%。

filter + 向量混合查

-- 找符合 metadata + 最近向量
SELECT content
FROM chunks
WHERE lang = 'zh'
  AND created_at > '2025-01-01'
ORDER BY embedding <=> $query LIMIT 10;

PG 查询计划器自动选 index。带 filter 时 HNSW + B-tree 配合(pg17+
更智能 prefilter)。

hybrid search

向量召回往往不如 keyword + 向量混合。

def hybrid_search(query, k=10):
    # 1. BM25 (PG FTS)
    bm25_results = pg.execute("""
        SELECT id, ts_rank(...) AS score
        FROM chunks WHERE chunk_tsv @@ to_tsquery(%s)
        ORDER BY score DESC LIMIT 50
    """, query)

    # 2. 向量
    vec_results = pg.execute("""
        SELECT id, 1 - (embedding <=> %s::vector) AS score
        FROM chunks
        ORDER BY embedding <=> %s::vector LIMIT 50
    """, [vec, vec])

    # 3. RRF (Reciprocal Rank Fusion)
    return rrf_merge(bm25_results, vec_results, k=k)

实际 RAG 效果显著提升。pgvector / Qdrant 都有内置 hybrid(不同程度)。

embedding model 选

  • OpenAI text-embedding-3-small / large:好但要 API
  • bge-m3 / bge-large-zh(BGE 系列):开源中英双语强
  • nomic-embed-text-v1.5:开源,128 维 - 768 维可调
  • e5-mistral-7b:高质量但贵
  • multilingual-e5-large:100+ 语言

中文 RAG 我用 bge-m3,足够好 + 开源 + 本地 GPU 跑(~150 MB model)。

真实 case:知识库 RAG

我们一个内部知识库:

  • 5 万文档 / 切 chunk 后 30 万段
  • 用 bge-m3 embedding(1024 维)
  • 存 pgvector
  • query:BM25 + vector hybrid

部署:

  • Postgres 16 + pgvector 0.7
  • 单 16 GB RAM 服务器
  • query P50: 50 ms(含 embed 模型推理)

成本:$50/月 server,对比 Pinecone $200+。
功能足够,没必要专门 vector DB。

chunk 策略

向量质量第一影响 chunk:

  • 太大(> 1000 token):embedding 模糊,定位差
  • 太小(< 100 token):上下文缺失
  • 重叠(10-20%):边界 case

通用 500 token + 100 overlap。技术文档可能 800 + 150。

踩过的坑

  1. pgvector index 建得慢:百万 vector 建 HNSW 30 分钟。
    SET maintenance_work_mem = '2GB' 加快。

  2. embedding dimension 改了:换模型 → 维度变 → 老数据 schema 不
    兼容。必须重新索引全部。

  3. filter selectivity 低 + 向量查:query plan 选 seq scan vector
    field(不走 HNSW)。SET enable_seqscan = off 测试。

  4. cosine vs dot:normalized vector 用 cosine OK;non-normalized
    用 dot product。混 → 结果错。

  5. vector 类型 cast'[0.1]'::vector JSON-like 字符串。从
    list [0.1, 0.2] 转字符串小心 numpy float 序列化精度丢失。

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。