mysql的spatial索引仅支持最多4维几何对象,强行将768维向量映射为point会导致截断或报错,且高维语义在降维后严重失真;其r-tree设计面向地理坐标,无法支撑高维向量的距离可分性与ann检索需求。

MySQL 本身不支持原生向量索引,所谓“近似索引搜索”必须靠外部工程手段模拟或绕过其 B+ 树限制——直接用 WHERE 加 ORDER BY 配合 COSINE 或 EUCLIDEAN 计算,本质仍是全表扫描,数据量一过百万,延迟就不可控。
为什么不能依赖 MySQL 的 SPATIAL 索引做高维向量检索
MySQL 的 SPATIAL 索引(R-Tree)只支持二维或三维几何对象,比如 POINT(x, y) 或 POLYGON。你强行把 768 维向量塞进 POINT 会触发错误:ER_CANT_CREATE_GEOMETRY_OBJECT,或者被截断为前两维,完全丢失语义信息。即便降维到 2D 再建索引,召回率也会断崖式下跌——Nomic-Embed-Text-V2-MoE 或 BGE-Large-Zh 的向量结构在高维空间才有意义,投影破坏距离可分性。
- 官方文档明确限定:R-Tree 最多支持 4 维,且仅用于地理坐标场景
-
ST_Distance函数默认用欧氏距离,但无法扩展到 >3 维;自定义函数无法走索引 - 即使成功建了
SPATIAL索引,EXPLAIN 显示实际执行仍为type: ALL(全表扫描)
用 JSON + 表达式索引加速部分过滤,但不解决核心相似度计算
如果你的查询带强业务约束(比如“只查 2025 年之后、状态为 active 的商品”),可以利用 MySQL 8.0+ 的表达式索引 + JSON 字段做前置剪枝,大幅缩小候选集规模,再对小集合做向量比对。这不提升单次向量计算速度,但能避免无谓扫描。
- 建表时用
vector_json JSON存原始向量,同时加生成列:vec_norm FLOAT AS (JSON_EXTRACT(vector_json, '$[0]')) STORED - 对生成列建普通 B+ 树索引:
INDEX idx_vec_norm (vec_norm),配合WHERE vec_norm BETWEEN -0.1 AND 0.1快速排除明显不相关的块 - 注意:
JSON_EXTRACT提取单个维度效率尚可,但无法提取全部 768 维做批量计算;点积或余弦仍需 Python/应用层完成 - 该策略在 Lychee 模型的 512 维特征场景中实测可将候选集从 200 万条压到 5 万条,后续向量比对耗时从 1200ms 降到 80ms
真正可行的方案:MySQL 只存元数据,向量交给 Milvus / Qdrant
当向量维度 ≥128、总量 ≥10 万条时,硬刚 MySQL 向量检索就是给自己埋坑。正确分工是:MySQL 负责 item_id、price、category 等结构化字段的 ACID 事务和关联查询;Milvus 或 Qdrant 负责 vector 的 ANN 检索。两者通过 ID 关联,混合查询由应用层拼接。
- Milvus 的
HNSW索引在 1000 万 768 维向量上,P99 延迟稳定在 15ms 内;MySQL 全表扫同样数据要 8s+ - Qdrant 支持
filter参数,在向量检索时直接下推元数据条件(如price > 100),避免 MySQL → 应用 → 向量库的多次往返 - 不要试图用
FLOAT列存向量:768 个DOUBLE占 6KB/行,IO 成瓶颈;BLOB虽省空间但无法索引任何维度 - 如果必须单库,MariaDB 10.11+ 的
VECTOR类型(实验性)支持内积运算和简单索引,但生产环境兼容性和生态工具链远不如专用向量库
高维向量检索的“优化”不是调几个 MySQL 参数就能解决的事——它本质是选对存储范式。把向量塞进关系型数据库的字段里,就像用螺丝刀拧螺母:能转,但越用力越滑牙。真正卡住性能的从来不是 SQL 写得不够巧,而是底层数据结构与问题域的根本错配。











