给一批文档做语义搜索时,最先想到的是把内容存进数据库再用 LIKE 查。结果发现 LIKE 只能匹配字符,没法理解「意思差不多」这回事。改用向量数据库后,第一感觉是:它只是换了一种索引,实际连数据模型都要重新想一遍。整理一下两类数据库在使用上的差异。

数据模型:行 vs 向量

传统数据库把数据组织成表:字段固定、类型固定,每行是一个业务实体。向量数据库存的是 embedding(模型生成的浮点数数组)加元数据,向量维度在建 collection 时固定,元数据字段可以随内容增减。

# 向量数据库里的一条记录,可以只有向量 + 元数据
{
  "id": "doc_001",
  "vector": [0.12, -0.03, 0.87, ...],  # 768 维
  "metadata": {"title": "Docker 数据卷", "author": "youyou", "created": "2026-08-01"}
}

元数据不是主数据。向量库里的 content 通常只存切分后的片段,原始文档仍放在关系库或对象存储里,用 id 关联。

查询方式:等值 vs 相似度

传统数据库的核心操作是等值、范围、排序、关联:

SELECT * FROM orders
WHERE user_id = 1024 AND amount >= 100
ORDER BY created_at DESC
LIMIT 20;

向量数据库的核心操作是「找最接近的 K 个」。以 pgvector 为例,普通 SQL 里也能写距离查询:

SELECT content, embedding <=> $1 AS distance
FROM documents
ORDER BY embedding <=> $1
LIMIT 5;

<=> 是余弦距离,<-> 是欧氏距离,<#> 是点积。选哪个由 embedding 模型决定:模型按相似度训练时用余弦,按语义方向训练时用点积。这个差别在传统数据库里没有对应物。

维度传统数据库向量数据库
查询目标等于、大于、范围、join与给定向量最相似的 top-k
返回结果满足条件的行相似度分数 + 行
索引B-Tree、Hash、倒排索引HNSW、IVF、PQ
Schema固定,改表要迁移向量维度固定,元数据灵活
事务ACID 完整多数只保证最终一致
写入方式单条和批量都常见批量写入为主,单条高频写入会拖慢索引

索引的成本结构

传统数据库的 B-Tree 按值排序,查询代价和匹配条数、索引命中有关。向量数据库没有「值」可排序,精确的最近邻要遍历全部向量算距离,数据量上去后不可行,所以用 ANN(近似最近邻)索引换速度,代价是召回率不再是 100%。

常用索引里:

  • HNSW:图结构,查询快、召回高,内存占用大
  • IVF:先聚类缩小范围,省内存,参数调不好召回会掉
  • PQ:向量压缩,省内存,精度损失最大

过滤字段是否支持索引,决定元数据过滤会不会退化成全表扫,不同向量库差异很大。

写入和更新的差异

传统数据库对高频小写入、原地更新很友好,事务保证并发下的正确性。向量数据库的写入链路更长:内容要先切分、过 embedding 模型生成向量,再批量写入;单条插入不是瓶颈,反复更新删除会让索引碎片化,性能逐步变差。

实践中多用「先写业务库,再异步同步到向量库」的结构:

原始文档 → 关系库(来源数据)
         ↘ 切分 → embedding → 向量库(检索副本)
查询:向量库召回 chunk_id → 回关系库取详情

两类库不是二选一

独立向量库(Milvus、Qdrant、Weaviate)和传统数据库的向量扩展(pgvector、SQLite vec)解决的是同一件事:向量检索。差别在规模:小数据量用扩展省一套组件,数据量大、需要横向扩展时再上独立向量库。

判断场景时可以看查询性质:

  • 要等值、范围、事务 → 传统数据库
  • 要按语义相似度找 → 向量数据库
  • 两者都要 → 一个库带向量扩展,或两个库配合

核心区别:传统数据库回答「哪个值等于、大于什么」,向量数据库回答「哪个和它最像」。