给一批文档做语义搜索时,最先想到的是把内容存进数据库再用 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)解决的是同一件事:向量检索。差别在规模:小数据量用扩展省一套组件,数据量大、需要横向扩展时再上独立向量库。
判断场景时可以看查询性质:
- 要等值、范围、事务 → 传统数据库
- 要按语义相似度找 → 向量数据库
- 两者都要 → 一个库带向量扩展,或两个库配合
核心区别:传统数据库回答「哪个值等于、大于什么」,向量数据库回答「哪个和它最像」。