为什么 AI 应用需要一种"不精确"的数据库?本文从零开始,用对比的方式讲清向量数据库的存在理由。
一个 MySQL 回答不了的问题
假设你在做一个 AI 日记应用,用户输入**"最近心情比较好的户外活动"**,想把相关的日记找出来。
在 MySQL 里你能怎么做?
sql
-- 方案1:关键词匹配,但"心情好"不等于"心情愉快","户外活动"不等于"爬山"
SELECT * FROM diaries WHERE content LIKE '%心情好%' OR content LIKE '%户外%';
-- 方案2:全文索引,但还是基于词频,不懂"放松"和"愉快"是近义词
SELECT * FROM diaries WHERE MATCH(content) AGAINST('心情好 户外活动');
问题在于:MySQL 只能做符号层面的匹配,它不理解语义。
你真正想要的是:
把所有日记和"最近心情比较好的户外活动"比较一下,找出意思最接近的那几条。
这就是向量数据库要解决的问题。
两种数据库,两种世界观
MySQL:精确的"身份证"
MySQL 眼里的数据是一个个确定的字段值:
bash
┌──────┬──────────┬────────┬───────────┐
│ id │ name │ age │ city │
├──────┼──────────┼────────┼───────────┤
│ 1 │ 张三 │ 25 │ 北京 │
│ 2 │ 李四 │ 30 │ 上海 │
└──────┴──────────┴────────┴───────────┘
查询逻辑是二元的:命中 / 不命中。
sql
SELECT * FROM users WHERE age > 25 AND city = '北京';
-- 要么符合条件,要么不符合,没有"有点像"这回事
Milvus:模糊的"语义坐标"
Milvus 眼里的数据是一个个高维空间中的坐标:
csharp
"今天去公园散步了,心情愉快"
↓ Embedding 模型
[0.023, -0.150, 0.780, ..., 0.034] ← 1024 个浮点数
这个向量的意义在于:意思相近的文本,在向量空间里距离也近。
查询逻辑是连续的:有多相似?
arduino
"心情好的户外活动" → [0.019, -0.142, 0.791, ..., 0.028]
↓
和"公园散步"的距离: 0.92(很近!)
和"学习 Milvus"的距离: 0.23(很远)
一张表看清所有差异
| 维度 | MySQL | Milvus |
|---|---|---|
| 存什么 | 整数、字符串、日期 | 高维浮点向量 + 少量元数据 |
| 怎么查 | WHERE name = '张三' |
search(向量, top_k=10) |
| 匹配方式 | 精确比对(是/否) | 相似度计算(0~1 连续值) |
| 排序 | ORDER BY 手动指定 |
天然按相似度降序 |
| 索引 | B+Tree,确定性定位 | IVF/HNSW,近似定位 |
| 一条数据大小 | 几十字节 | 向量本身 4KB(1024维) |
| 能回答 | "id=5 的用户叫什么" | "哪些日记和这段文字最相似" |
索引的哲学差异
这可能是两者最本质的区别。
MySQL 的 B+Tree:确定性查找
ini
[30]
/ \
[15] [45]
/ \ / \
[1-15][16-30][31-45][46-60]
查询 age=25:
根节点 30 → 走左边 → 走到 15 的右子树 → 叶子节点中找到 25
✅ 命中就是命中,不存在"可能命中"
B+Tree 是一个精确导航系统------你知道目的地,它告诉你怎么走过去,绝不绕路。
Milvus 的 IVF:近似导航
makefile
向量空间被 K-Means 聚成 4 个簇:
┌────簇0─────┬────簇1─────┐
│ · · │ ·· │
│ ★ │ ★ │ ★ = 聚类中心
│ · ·· │ · ·· │
├────簇2─────┼────簇3─────┤
│ ·· · │ · ·· │
│ · ★ │ ★ ·· │
│ · ·· │ · · │
└────────────┴────────────┘
查询时:
① 查询向量和 4 个 ★ 比距离 → 找最近的 2 个簇
② 只在这 2 个候选簇里精确计算
③ 候选集从 100% 缩小到 ~20%,但可能漏掉簇边缘的数据
IVF 是一个猜路系统------你不知道数据在哪,但它大概率锁定对的区域,然后在这个区域里认真找。
为什么接受"近似"?
因为精确搜索的代价在大数据量下无法承受:
| 数据量 | 暴力搜索(逐一比对) | 索引搜索 |
|---|---|---|
| 1 万条 | ~10ms | <1ms |
| 100 万条 | ~1 秒 | ~5ms |
| 1 亿条 | ~100 秒 | ~20ms |
用 1-5% 的精度损失,换 100-10000 倍的性能提升。 在语义搜索场景下,Top-10 结果里少一个边缘相关的、多一个高度相关的,用户根本感知不到。
一个用代码说话的例子
用 Milvus Node.js SDK 来感受一下差别:
js
import { MilvusClient, IndexType, MetricType } from '@zilliz/milvus2-sdk-node';
// 连接
const client = new MilvusClient({
address: 'https://xxx.zillizcloud.com',
token: 'your-api-key',
});
// 建 Collection(简化模式,自动开启动态字段)
await client.createCollection({
collection_name: 'notes',
dimension: 4, // 演示用小维度
auto_id: true,
});
// 建索引
await client.createIndex({
collection_name: 'notes',
field_name: 'vector',
index_type: IndexType.AUTOINDEX,
metric_type: MetricType.COSINE, // 余弦相似度
});
// 插入几条测试数据
await client.insert({
collection_name: 'notes',
data: [
{ vector: [0.1, 0.2, 0.3, 0.4], content: '今天天气真好,适合出去玩' },
{ vector: [0.5, 0.6, 0.7, 0.8], content: '学习 AI 技术很有意思' },
{ vector: [0.15, 0.22, 0.28, 0.42], content: '阳光明媚,去公园散步' },
],
});
// 搜索:找和 [0.12, 0.21, 0.31, 0.39] 最相似的内容
const result = await client.search({
collection_name: 'notes',
data: [[0.12, 0.21, 0.31, 0.39]],
limit: 2,
output_fields: ['content'],
});
// 🥇 "今天天气真好,适合出去玩" (向量距离很近)
// 🥈 "阳光明媚,去公园散步" (向量距离也很近)
// 🥉 "学习 AI 技术很有意思" (向量距离更远,语义上不相关)
同样的查询如果用 MySQL 写,你只能靠 LIKE 或者全文索引去猜关键词------而关键词永远无法理解"天气真好"和"阳光明媚"其实在说同一件事。
所以,MySQL 和 Milvus 是替代关系吗?
不是。它们是互补关系。
一个 AI 产品同时需要这两种数据库:
yaml
┌──────────────────────────────────────────┐
│ 你的 AI 应用 │
│ │
│ MySQL / PostgreSQL: │
│ ├─ 用户注册登录 │
│ ├─ 订单、权限、配置 │
│ ├─ 文档元数据(标题、创建时间、作者) │
│ └─ 对话历史记录 │
│ ↑ 精确查询、事务、ACID │
│ │
│ Milvus: │
│ ├─ 知识库文档向量 │
│ ├─ 语义搜索 │
│ ├─ 长期记忆检索 │
│ └─ 相似内容推荐 │
│ ↑ 语义相似、向量搜索、ANN │
└──────────────────────────────────────────┘
MySQL 处理应用的骨架 (用户、订单、权限),Milvus 承载 AI 的灵魂(知识、记忆、语义理解)。
下一步
本文建立了向量数据库的基本认知。下一篇将深入向量索引的底层机制------IVF_FLAT 如何用聚类加速搜索,HNSW 如何用图结构导航,以及在实际项目中怎么选型。