前置知识: MySQL、MySQL

VECTOR 向量类型:MySQL 里的嵌入向量

4 min高级

MySQL 9 VECTOR 类型:声明与存储成本、三个转换函数、社区版与 HeatWave 的能力边界、应用层相似度检索的完整工作流与选型对照。

前置知识

  • 新特性版本策略(MySQL 9 新特性)——VECTOR 是 9.0 创新版引入的类型;
  • AI 应用背景(嵌入向量的来历见 Python 与 AI 路线)有助于理解用途,但不强制。

问题引入:向量塞 JSON 的土办法为什么不行

AI 应用要把文本/图片的嵌入向量(embedding,几百到几千个浮点数)持久化,最常见土办法是塞进 JSON 字符串列。代价:体积膨胀(JSON 文本比二进制浮点大数倍)、读取后要解析、无类型约束(维度错了存进去才发现)。MySQL 9.0 的 VECTOR 类型把它变成一等公民:二进制紧凑存储 + 维度校验 + 专用转换函数。

先立最重要的认知——版本能力边界(这是 VECTOR 相关网上资料最大的误导源):

能力社区版 9.xHeatWave(OCI 商业服务)
VECTOR 列存储与读取有有
转换函数(STRING_TO_VECTOR 等)有有
DISTANCE 距离函数无有
向量索引(近似最近邻)无有

一句话:社区版能”存”,不能在 SQL 里”搜”;检索要么应用层自己算,要么上 HeatWave 或专业向量库。

声明与读写

-- VECTOR(N):N 为维度;上限 16383 维。写入时维度不符直接报错(类型价值所在)
CREATE TABLE documents (
  id INT AUTO_INCREMENT PRIMARY KEY,
  content TEXT,
  embedding VECTOR(1536)          -- 对齐主流嵌入模型的 1536 维
);

-- 写入:JSON 数组形式的字符串,经 STRING_TO_VECTOR 转为二进制向量
INSERT INTO documents (content, embedding) VALUES (
  'MySQL is a relational database',
  STRING_TO_VECTOR('[0.1, 0.2, 0.3, ...]')
);

-- 读取:二进制向量必须转字符串才能看
SELECT id, content,
       VECTOR_TO_STRING(embedding) AS embedding_json,
       VECTOR_DIM(embedding) AS dims
FROM documents LIMIT 1;

存储成本要算在前面:每个分量 4 字节浮点,1536 维一行约 6KB,加上 JSON 元数据与页开销实际更高——百万行向量表就是数十 GB 级别,容量规划、内存命中率、备份时长都按这个量级估。选嵌入模型时维度直接决定这笔账(768 维比 3072 维省 4 倍)。

社区版的现实检索方案

既然社区版没有距离函数与索引,“找最相似的 K 条”怎么落地?三档方案按数据量选:

方案 A(万行级):全量取回 + 应用层算相似度
  SELECT id, content, VECTOR_TO_STRING(embedding) FROM documents;
  应用里与查询向量算余弦取 top K。零额外组件,几万行内完全够用

方案 B(十万行以上):向量出库,MySQL 只管业务字段
  向量存专业向量库(pgvector/Milvus/Qdrant/ES),
  MySQL 存业务数据并以主键关联。两段式:向量库召回 → MySQL 补全业务字段

方案 C(Oracle 技术栈):HeatWave
  DISTANCE 函数 + 向量索引,库内完成全部检索

方案 A 的应用层余弦相似度只需几行(Python 示意):

import json, math

def cosine(a: list[float], b: list[float]) -> float:
    dot = sum(x * y for x, y in zip(a, b))
    na = math.sqrt(sum(x * x for x in a))
    nb = math.sqrt(sum(y * y for y in b))
    return dot / (na * nb)

rows = query("SELECT id, VECTOR_TO_STRING(embedding) v FROM documents")
q = embed("数据库入门")            # 调嵌入模型得到查询向量
top = sorted(rows, key=lambda r: -cosine(q, json.loads(r["v"])))[:5]

这个工作流的完整版(含 RAG 场景、召回率评测)在 PostgreSQL KNN 篇 有对位展开——pgvector 的索引与算子正是 MySQL 社区版缺失的那一半。

动手环节:社区版全流程体验

-- 1. 建表与写入(4 维迷你向量,机制与 1536 维完全一致)
CREATE TABLE vec_demo (
  id INT AUTO_INCREMENT PRIMARY KEY,
  txt VARCHAR(100),
  vec VECTOR(4)
);
INSERT INTO vec_demo (txt, vec) VALUES
  ('数据库教程', STRING_TO_VECTOR('[0.9, 0.8, 0.1, 0.2]')),
  ('数据库原理', STRING_TO_VECTOR('[0.85, 0.9, 0.05, 0.1]')),
  ('红烧肉做法', STRING_TO_VECTOR('[0.1, 0.2, 0.9, 0.8]'));

-- 2. 维度校验是类型级的(写入 5 维直接报错)
-- INSERT INTO vec_demo (txt, vec)
-- VALUES ('坏数据', STRING_TO_VECTOR('[1,2,3,4,5]'));
-- ERROR 3854 (HY000): Dimension mismatch

-- 3. 读回验证
SELECT txt, VECTOR_TO_STRING(vec), VECTOR_DIM(vec) FROM vec_demo;

-- 4. 亲测社区版边界:距离函数不存在
-- SELECT DISTANCE(vec, STRING_TO_VECTOR('[0.9,0.8,0.1,0.2]'), 'COSINE') FROM vec_demo;
-- ERROR 1305: FUNCTION DISTANCE does not exist —— 印证能力边界表

-- 5. 网上示例的陷阱复现:向量索引语句同样不可用
-- ALTER TABLE vec_demo ADD VECTOR INDEX ((vec));
-- 同样报错——社区版读到这段语法的教程请直接关闭

第 2 步与第 4 步分别验证了 VECTOR 类型的”有所为”(维度约束)与”有所不为”(检索)——把能力边界亲手戳一遍,胜过背十遍对照表。

常见困惑

“为什么不直接用 JSON 数组列?“——三项差距:体积(4 字节二进制 vs 每个数 10+ 字符的文本);类型安全(VECTOR 在写入时校验维度,JSON 列什么都收);语义(VECTOR_TO_STRING/VECTOR_DIM 等配套函数,JSON 要自己解析)。检索能力上两者半斤八两(都得应用层算)——所以正确对比是”VECTOR vs JSON”选存储,“MySQL vs 向量库”选检索。

“MySQL 会把向量索引下放到社区版吗?”—— Oracle 的商业策略上向量检索(HeatWave)与 MySQL HeatWave 产品深度绑定,社区版短期内大概率维持”只存不搜”。做技术选型按现状评估,别按路线图赌。

“该选 MySQL+向量库 还是直接 PostgreSQL+pgvector?“——若项目本来就以 MySQL 为主、向量规模在 pgvector 舒适区之外,方案 B(MySQL 业务库 + 独立向量库)干净直接;新项目且向量检索是核心能力,pgvector 把存储与检索收在一个库里,工程链路更短。判据是”检索在业务里的权重”,不是数据库偏好之争。

检验清单

  • 能默写社区版与 HeatWave 的能力边界表,并说出它为什么是 VECTOR 第一知识点;
  • 会声明带维度的 VECTOR 列并完成三个转换函数的读写闭环;
  • 算得清 1536 维百万行的存储账,理解维度选择即容量选择;
  • 完成社区版实验:维度校验报错、DISTANCE 报错、索引语句报错三连验证;
  • 能按数据量在应用层余弦/独立向量库/HeatWave 三档方案中给出选型。

下一步

向量只是 MySQL 9 的特性之一:回看 MySQL 9 新特性总览 补全版本演进全景;AI 检索的完整工程(RAG、评测、成本)则继续 Python 与 AI 路线。