第03章:数据库选型——PostgreSQL+pgvector与ChromaDB对比

第03章:数据库选型——PostgreSQL+pgvector与ChromaDB对比


3.1 选型原则:不要为了技术复杂度买单

数据库选型是企业级AI项目里最容易被"过度设计"的环节。选型时有两个核心原则:

  1. 能跑通再优化:先用最简单的方案跑通核心流程,瓶颈出现再针对性升级
  2. 团队能维护:选团队真正能驾驭的工具,不是理论上最优的工具

本章对比三种向量存储方案,帮助你在不同场景下做正确选择。


3.2 方案一:PostgreSQL + pgvector(推荐生产方案)

pgvector 是 PostgreSQL 的扩展,在PG里直接支持向量类型和向量索引。

核心优势

  • 单一数据库:结构化数据(顾客档案)和向量数据(知识库embedding)在同一个库,省去同步麻烦
  • ACID保障:事务支持完整,数据一致性与PostgreSQL同级别
  • SQL全家桶:JSONB、全文搜索、窗口函数……全部可用
  • 运维简单:一个数据库实例搞定所有,不用多跑一套Milvus/Chroma服务
  • 社区成熟:PG16+pgvector的生产案例已经很多,踩坑成本低

局限性

  • pgvector 的 ANN 索引(IVF-Flat、HNSW)在超大规模数据量(>1亿条)下性能不如专业向量数据库
  • 安装需要数据库服务器支持扩展(部分云PG厂商暂不支持)

安装方式

# Docker 方式(一键)
docker pull pgvector/pgvector:pg16
docker run -d --name pgvector \
  -e POSTGRES_PASSWORD=yourpassword \
  -p 5432:5432 \
  pgvector/pgvector:pg16

# 已有的PG实例追加扩展
CREATE EXTENSION IF NOT EXISTS vector;

# 向量字段定义(1536维,适配 bge-small-zh/bge-base 等)
ALTER TABLE medical_knowledge
ADD COLUMN embedding vector(1536);

# 创建 HNSW 索引(查询性能更好)
CREATE INDEX ON medical_knowledge
USING hnsw (embedding vector_cosine_ops);

# 创建 IVF-FLAT 索引(内存占用更低)
CREATE INDEX ON medical_knowledge
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

增删改查示例

-- 插入带向量
INSERT INTO medical_knowledge (title, content, category, embedding)
VALUES (
  '光子护理适合人群',
  '光子护理适合面部有雀斑、晒斑、毛孔粗大、肤色不均的人群。敏感肌需谨慎。',
  '抗衰',
  '[0.123, -0.456, ...]'  -- 1536维向量
);

-- 相似性检索(余弦相似度)
SELECT title, content,
       1 - (embedding <=> '[0.1, 0.2, ...]'::vector) AS similarity
FROM medical_knowledge
WHERE category = '抗衰'
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 5;

-- 过滤 + 向量检索组合
SELECT * FROM medical_knowledge
WHERE forbidden = FALSE
  AND category = '抗衰'
ORDER BY embedding <=> '[query_vector]'::vector
LIMIT 3;

3.3 方案二:ChromaDB(轻量原型方案)

ChromaDB 是一个专门为 AI 应用设计的向量数据库,安装简单,API直观,适合快速原型验证。

核心优势

  • 零配置:pip install 后直接用,不需要跑服务器
  • API 极简:add/query/delete 三条命令搞定所有操作
  • 自带持久化:本地文件存储,重启不丢数据
  • Python 原生:和 Pandas/NumPy 无缝衔接

局限性

  • 纯向量库,没有结构化字段(顾客档案等仍需存在PG里,形成双库架构)
  • 并发写入性能一般(单实例,写入需要加锁)
  • 删改查的灵活性不如 pgvector(不支持复杂过滤条件)
  • 部署在生产环境时需要封装成独立服务

安装与使用

# 安装
pip install chromadb

# 基本使用
import chromadb

client = chromadb.PersistentClient(path="./chroma_data")

# 创建集合(类似表)
collection = client.create_collection(
    "medical_knowledge",
    metadata={"description": "美业知识库"}
)

# 添加向量数据
collection.add(
    ids=["kg_1", "kg_2"],
    embeddings=[[0.1, 0.2, ...], [0.3, 0.4, ...]],  # 向量
    documents=["光子护理适合人群...", "水光针适合人群..."],  # 原文
    metadatas=[{"category": "抗衰"}, {"category": "抗衰"}]
)

# 语义检索
results = collection.query(
    query_embeddings=[[0.15, 0.22, ...]],
    n_results=3
)
# results["documents"][0] → 最相似的3条知识

双库架构下的数据一致性

当知识库同时存在 PG 和 ChromaDB 时,新增/修改/删除操作必须双写

def add_knowledge(title, content, category):
    pg_id = insert_into_pg(title, content, category)      # 写PG
    vector = get_embedding(f"{title}:{content}")          # 生成向量
    add_to_chroma(f"kg_{pg_id}", vector, content)         # 写ChromaDB

def delete_knowledge(pg_id):
    delete_from_pg(pg_id)           # 删PG
    delete_from_chroma(f"kg_{pg_id}")  # 删ChromaDB

3.4 方案三:混合方案(大型项目)

当项目规模变大,可以考虑:

数据类型 存储方案
顾客档案、订单(结构化+事务) PostgreSQL(已有)
知识库向量(>100万条) Qdrant / Milvus(专用向量库)
缓存热点数据 Redis
文件(文档、图片) S3 / MinIO

Qdrant 是这两年表现很不错的开源向量数据库,有 Rust 和 Python 客户端,支持过滤条件,生产性能优秀。


3.5 三方案横向对比

维度 pgvector ChromaDB Qdrant/Milvus
安装难度 中(需PG扩展) 低(pip即用) 高(需单独部署)
结构化+向量 ✅ 单一数据库 ❌ 需双库 ❌ 需双库
查询灵活性 ✅ 极致(SQL) ⚠️ 弱 ⚠️ 中等
百万级向量性能 ⚠️ 中等 ❌ 差 ✅ 优秀
事务支持 ✅ 完整ACID ❌ 无 ❌ 无
团队熟悉度 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐
推荐场景 生产首选 原型/轻量 超大规模

本书实战选择:先用 ChromaDB 跑通原型(美容案例就是用的这个),等数据量超过50万条时平滑迁移到 pgvector 或 Qdrant。


3.6 Embedding 模型与向量维度

向量维度由 Embedding 模型决定,选型时必须匹配:

模型 向量维度 中文支持 推荐场景
bge-small-zh 512 ✅ 强 轻量/快速(本书用这个)
bge-base-zh 768 ✅ 强 平衡(推荐)
text2vec-base-chinese 768 ✅ 强 平衡
m3e-base 768 ✅ 强 平衡
bge-large-zh 1024 ✅ 强 高精度

注意:ChromaDB 建 Collection 时会根据首次插入的数据自动推断向量维度。如果 Ollama 的 Embedding 模型输出维度与已有 Collection 不匹配,会报 dimension 错误。删除 chroma_data/ 目录重建即可。


落地动作

  1. 确认你的 PostgreSQL 是否支持 pgvector 扩展(如果没有,用 Docker 拉取官方镜像)
  2. 用 pip 安装 chromadb,python -c "import chromadb; print(chromadb.__version__)" 验证
  3. 运行一次本地的向量插入和检索测试(参考本章代码)
  4. 如果数据量预估 >50万,提前规划 pgvector 迁移路径