做过 RAG 的人大概都干过这么一件事。
数据本来在 MySQL 里好好躺着,为了做检索,又搭了一套向量库。写个管道把数据同步过去,然后开始维护两套权限、两份备份、两条会各自出故障的链路。同步延迟了要查,向量库挂了要查,两边的数据对不上了还得查。
模型选型纠结了两个礼拜,真正耗人的其实是这套搬运工程。
MySQL 从 9.0 开始给了一条不用搬的路:向量可以直接当列存,检索、嵌入、问答都能在库内完成,入口还是那条 SQL。
这篇把这条路走一遍:三块能力分别是什么、社区版能玩到哪一步、本地怎么部署、代码怎么写、以及最实在的——什么规模下这条路走得通,什么时候还是得去搬。
一、先分清三块能力,能少走弯路
MySQL 的 AI 能力不是一坨东西,是三块。它们的可用范围差别很大,混着看最容易在动手时才发现「我这个版本怎么没有」。
| 能力 | 从什么时候有 | 社区版 | 说明 |
|---|---|---|---|
| VECTOR 列(存取 + 格式转换) | MySQL 9.0 | ✅ 可用 | 能建列、写入、读出;配套STRING_TO_VECTOR()/VECTOR_TO_STRING() |
距离计算DISTANCE() | 随 VECTOR 类型引入 | 需自查版本 | 支持余弦、点积、欧氏距离三种度量 |
库内嵌入ML_EMBED_ROW/ML_EMBED_TABLE | MySQL AI / HeatWave GenAI | ❌ | 由库内模型把文本转成向量 |
RAG 问答ML_RAG+ 向量存储 | 同上 | ❌ | 检索出相关段落 → 大模型组织答案 → 附引用 |
AutoMLML_TRAIN | 同上 | ❌ | 分类 / 回归,训练和预测都走 SQL |
| 混合检索(语义 + 关键词) | HeatWave MySQL 9.5.0 起 | ❌ | 语义相似和关键词命中合并查 |
一句话记法:VECTOR 列是社区版就能碰的,剩下的库内能力都落在两个地方——企业版的本地部署(MySQL AI),或者云上的 HeatWave。
DISTANCE()与 VECTOR 类型同期引入,具体可用范围在各版本间有差异,在你的实例上直接跑一句SELECT DISTANCE(STRING_TO_VECTOR('[1,0]'), STRING_TO_VECTOR('[0,1]'), 'COSINE');就能确认,比翻文档快。
二、向量列到底长什么样
先建立直觉。一个向量就是一串小数,用来表示一句话或一段文档在「意思」上的位置——意思越接近,这串小数也越接近。
几个硬性规格:
- 默认长度2048 维,上限16383 维;
- 每一维是一个单精度浮点数;
- 目前不能当主键,也不能建普通索引。
前两条影响存储,第三条影响架构,都得算。
2.1 先算一笔存储账
单精度浮点每维 4 字节,所以:
| 维度 | 单行向量体积(粗略量级) | 100 万行 |
|---|---|---|
| 384 维(常见 MiniLM 类模型) | 约 1.5 KB | 约 1.5 GB |
| 2048 维(MySQL 默认) | 约 8 KB | 约 8 GB |
| 16383 维(上限) | 约 64 KB | 约 64 GB |
(这是纯向量部分的数量级估算,不含行开销、原文本和日志。)
结论很直接:别用默认的 2048 维一把梭。用什么维度由你的嵌入模型决定,模型定了维度就定了。选模型时顺手把这张账算一遍,比事后发现磁盘告警强。
2.2 「不能建索引」意味着什么
这是全文最该被记住的一条限制。
向量列不能建索引,意味着ORDER BY DISTANCE(...) LIMIT k这类查询只能全表扫描——每次提问都要把整张表的向量算一遍距离。
它直接决定了这条路能撑多大:
- 几万到几十万行:完全没问题,SQL 一把梭,省掉整套向量基础设施;
- 上百万行以上:扫描成本会开始咬人,召回方式和维度都得按官方文档重新设计,这时候专门的向量库大概率是更划算的选择。
先估行数,再决定要不要走这条路。这一步花五分钟,能省掉后面几个月的重构。
三、完全本地跑:MySQL AI 是什么
如果你的要求是「AI 功能整个留在我自己的机器上」,对应的产品是MySQL AI——MySQL 企业版的本地部署选项。内置大模型、向量存储、AutoML 都在本地环境里。
有个特别舒服的点:模型跑在 CPU 上,不用单独配 GPU。
3.1 装之前先看门槛
| 项 | 要求 |
|---|---|
| 许可 | MySQL 企业版许可 |
| 操作系统 | Oracle Linux 8 / Red Hat Enterprise Linux 8 |
| 官方参考配置 | 32 逻辑 CPU、128 GB 内存、512 GB 磁盘 |
| 模型运行 | CPU,无需 GPU |
| 文档目录 | 安装时指定一个允许读取的目录,默认常见是/var/lib/mysql-files |
门槛不低,这决定了它更适合有一定规模的团队,而不是个人开发者拿来试手。
3.2 把一份文档装进向量存储
-- 读入 → 切段 → 编码 → 写入向量表,一条语句搞定CALLsys.VECTOR_STORE_LOAD('file:///var/lib/mysql-files/demo-directory/return-policy.pdf',@options);文档放在本机目录里就行,路径用file://指向它。
路径要按环境换:本地 MySQL AI 是file://指向的本机目录,云上 HeatWave 则从对象存储读。这是本地和云之间少数需要改的地方之一。
问法还是后面那套ML_EMBED_ROW、ML_RAG、ML_TRAIN,名字完全一样。
3.3 为什么推荐「先在本地写」
这是这套设计里我认为最值钱的一点:
先在本地用 MySQL AI 把应用写出来,以后需要更好的性能和更丰富的功能,再迁到云上的 HeatWave——应用代码不用改。
两边的问答和训练例程是同一套。对团队来说,这意味着不用一开始就在架构上做不可逆的决定,可以先把业务跑通。
四、RAG 到底在干什么:一个客服的例子
想象一家小店的客服。顾客问:「这件衣服不合适,几天内能退?」
退货规则写在退货说明那份 PDF 里。顾客当然不会自己去翻。
MySQL AI 和 HeatWave 走的是同一条路:
大模型见过很多公开资料,但未必见过你店里的退货规则。
所以先把你自己的文档变成向量放进表里,回答时只挑出相关的那几段当依据。答案贴着你的制度走,而且方便回头核对原句——这一点比答案本身更重要。
这也是 RAG 和「直接把问题丢给大模型」的根本区别:前者能给出处,后者只能给一个听起来很像的答案。
五、三个能直接跑的例子
第一段在 MySQL 9 上就能体会向量列长什么样。后两段在 MySQL AI 和 HeatWave 上都能用,例程名字一样。
例子里的向量只用 3 维,是为了让人眼能看懂。手写这几个小数只为演示,真实嵌入由模型生成,通常是几百维,而且必须和提问用同一个模型。
5.1 建一张带向量列的问答表
-- MySQL 9 社区版即可运行CREATEDATABASEdb_shop;USEdb_shop;CREATETABLEt_faq(idINTUNSIGNEDAUTO_INCREMENTPRIMARYKEY,questionVARCHAR(200)NOTNULL,answerTEXTNOTNULL,embedding VECTOR(3)NOTNULL-- 演示用 3 维;生产通常是几百到上千维);INSERTINTOt_faq(question,answer,embedding)VALUES('怎么退货','签收后 7 天内可申请退货。',STRING_TO_VECTOR('[0.90, 0.10, 0.05]')),('运费怎么算','满 99 元包邮,否则收取 8 元。',STRING_TO_VECTOR('[0.10, 0.85, 0.15]')),('会员有什么权益','会员下单享 9 折,生日当月再减 20 元。',STRING_TO_VECTOR('[0.15, 0.10, 0.90]'));SELECTid,question,VECTOR_TO_STRING(embedding)ASembedding_textFROMt_faq;注意两个函数的用法:
STRING_TO_VECTOR()吃的是带方括号的字符串;VECTOR_TO_STRING()把它变回人能读的样子;TO_VECTOR()、FROM_VECTOR()分别是这两个函数的同义词,见到不用困惑。
5.2 找和问题最接近的答案
用余弦距离把「想退货」这种问法对上退货那一行。距离越小,越接近。
-- MySQL AI / HeatWave 上可直接运行SET@q=STRING_TO_VECTOR('[0.88, 0.12, 0.06]');SELECTid,question,answer,DISTANCE(embedding,@q,'COSINE')ASscoreFROMt_faqORDERBYscoreLIMIT2;第三个参数还能换成'DOT'(点积)或'EUCLIDEAN'(欧氏距离)。
| 度量 | 写法 | 特点 |
|---|---|---|
| 余弦距离 | 'COSINE' | 只看方向不看长度,文本检索最常用 |
| 点积 | 'DOT' | 对向量长度敏感,适合已归一化的向量 |
| 欧氏距离 | 'EUCLIDEAN' | 看绝对距离,适合作 embedding 聚类 |
这里返回的score是距离,小的排在前面——和「相似度分数」的习惯正好相反,写排序的时候别弄反。
5.3 让数据库按你的文档回答
真实项目里,向量交给嵌入模型生成。
-- 单句嵌入SET@text='签收后 7 天内可以退货,运费满 99 元包邮。';SELECTsys.ML_EMBED_ROW(@text,JSON_OBJECT('model_id','all_minilm_l12_v2'))INTO@text_embedding;整表文本用sys.ML_EMBED_TABLE。PDF 这类文件先装进向量存储(本地走上一节的file://路径,云上从对象存储读)。
然后问答:
SET@query='What is the return window?';SET@options=JSON_OBJECT('vector_store',JSON_ARRAY('db_shop.demo_embeddings'),'model_options',JSON_OBJECT('language','en'));CALLsys.ML_RAG(@query,@output,@options);SELECTJSON_PRETTY(@output);返回的 JSON 里两个字段最关键:
text:模型组织好的回答;citations:它参考过的段落和距离——这是你能核对答案的依据。
language用两位语言代码,默认是en。做中文知识库别忘改这个值,而且先看你当前版本文档里支持的语言列表再填。
5.4 顺带说一句 AutoML
如果还想做预测——比如订单表里有一列「会不会再次购买」——那是另一条路。MySQL AI 和 HeatWave 都提供这组例程:
CALLsys.ML_TRAIN('db_shop.t_order','will_buy_again',JSON_OBJECT('task','classification'),@model);这两件事经常被混为一谈,其实解决的问题完全不同:
- 问答(RAG):找相似段落 → 生成回答;
- 预测(AutoML):用历史数据 → 学一个分类模型。
相同的地方是,都用 SQL 发起,数据都留在原来的库里。
六、本地还是云:怎么选
| 你的情况 | 选什么 | 注意 |
|---|---|---|
| 已经在用 MySQL,希望客服、制度、产品说明能被直接问到 | 本地跑用企业版 MySQL AI;能上云就用 HeatWave GenAI | 两边例程同一套 |
| 数据不能出机房 | 本地 MySQL AI | 模型跑在 CPU 上,无需 GPU |
| 想先跑通再扩容 | 本地开发 → 迁 HeatWave | 应用代码不用改 |
只是想让社区版先认识VECTOR这种列 | 社区版,跑本文 5.1 那段 | 到DISTANCE()之后就得出 AI 版 |
| 数据量上百万行以上 | 先评估,或考虑专门的向量库 | 向量列不能建索引,全表扫描 |
七、现在就能用吗:五条实话
第一,向量列不能建索引,这条前面说过,但它值得再出现一次。数据量上来之后,召回方式和维度都得按文档重新设计。示例代码是用来把路走通的,上生产前必须按你的真实数据量再跑一遍。
第二,嵌入模型必须一致。问题和文档要用同一个模型编码。MySQL 9.2.1 之后,检索会按嵌入模型去匹配同一套向量表——换模型意味着重建整张向量表,这个成本要提前算进去。
第三,中文知识库记得改language,默认是英文。改之前先确认当前版本支持的语言列表。
第四,本地部署门槛不低:企业版许可、Oracle Linux 8 / RHEL 8、32 核 128G 起步的参考配置。个人探索可以只玩社区版的 VECTOR 列。
第五,边界要认。这套方案省掉了「数据搬家」,但省不掉「规模」。几十万行以内,它是性价比极高的选择;到了千万级,专门的向量数据库依然是更合适的工具。这不是 MySQL 不行,是它本来的定位就是那个存订单、跑事务的库。
八、小结
MySQL 还是那个 MySQL。
网站的用户表、订单表、库存表躺在里面,事务保证扣库存和写订单一起成功或一起回滚,主从复制、备份、权限把它撑到能上线——这些都没变。
变化在于,按意思找资料、生成一段带出处的回答,也可以从同一条 SQL 会话里开始了。
工具链少一套,就少一份要维护的东西。这可能是这次更新里最实际的价值。