使用原生向量索引进行相似性检索

更新时间:
复制 MD 格式

云原生数据库PolarDB分布式版在 MySQL 生态中原生提供向量存储与检索能力。您可以用标准 SQL 定义向量字段、写入向量数据,并通过 ORDER BY VEC_DISTANCE(...) LIMIT N 完成高性能的近似最近邻(ANN)相似度检索,适用于语义搜索、推荐召回、图文多模态检索、RAG(检索增强生成)等 AI 场景。

功能简介

向量索引底层基于业界主流的 HNSW(Hierarchical Navigable Small World)算法,并复用 InnoDB 的事务、持久化、崩溃恢复与主备复制能力,让您像使用普通索引一样使用向量索引。

向量索引解决的核心问题是:在海量高维向量中,快速找到与目标向量最相似的 Top-N 条记录。

核心特性

PolarDB-X向量索引的主要特性如下:

特性

说明

最大维度

支持最高 16,383 维

数据类型

单精度浮点(float32)

距离度量

EUCLIDEAN(欧氏距离)、COSINE(余弦距离)

索引算法

HNSW 多层图结构

硬件加速

自动启用 AVX512 / AVX2 / ARM NEON 指令集加速距离计算

事务支持

支持已提交读(Read Committed,RC) /可重复读(Repeatable Read,RR) /串行化(SERIALIZABLE)隔离级别

复制与高可用

支持Binlog复制、XA事务,主备数据一致。企业版支持分布式事务。

适用范围

您的实例需满足以下版本要求:

  • 产品系列:标准版或企业版。

  • 引擎版本:MySQL 8.0。

  • 存储节点版本:V2.6.0.8.4.21-20260605 及以上版本。

    说明
  • 向量数据的写入、更新、删除与基表在同一事务内自动同步,无需手动维护索引,使用体验与普通索引一致。不同实例产品系列支持能力有所不同:

    能力

    标准版(集中式)

    企业版(分布式)

    向量存储与ANN检索

    支持

    支持

    主备复制/高可用

    支持

    支持

    事务

    支持

    支持

使用限制

  • 存储引擎:仅支持在InnoDB引擎表上创建向量索引。

  • 索引数量:同一张表当前仅支持创建一个向量索引。

  • 分区表 :暂不支持在标准版分区表上创建向量索引,企业版分区表支持创建向量索引。

  • DDL算法:创建、修改、删除向量索引使用COPY算法(非INPLACE),对大表会有较长的执行时间与锁定期,建议在业务低峰期操作。

  • INVISIBLE索引:向量索引不支持设置为INVISIBLE。

  • 向量数据约束:写入向量的维度必须与建表时 VECTOR(N) 的 N 严格一致,且不允许包含 NaNInf 值。

  • NULL 向量:向量列允许为 NULL。值为 NULL 的行不会被纳入向量索引,检索时不会被返回。

  • 空间膨胀UPDATE / DELETE 采用“标记删除 + 新增”方式维护图结构,高频更新或删除场景下辅助表会逐渐膨胀、召回率下降,需定期执行 OPTIMIZE TABLE 重建。

开启向量索引功能

向量索引功能由系统变量 vidx_disabled 控制,默认值为 ON(即默认关闭)。出于资源隔离考虑,需先显式开启后才能创建和使用向量索引。

说明

vidx_disabled 为反向开关:ON 表示关闭功能,OFF 表示开启功能。

方式一:(推荐)控制台修改

前往PolarDB分布式版控制台,在目标集群的配置与管理 > 参数设置页面的存储层页签中,将参数vidx_disabled修改为OFF

方式二:命令行修改

-- ON = 关闭,OFF = 开启
SET GLOBAL vidx_disabled = OFF;
说明

该变量修改后,已有连接不会立即生效,需重新建立连接后才能使用向量索引。

使用向量索引

创建向量字段与索引

向量字段使用 VECTOR(维度) 类型声明,例如:

标准版

CREATE TABLE articles (
    id        INT PRIMARY KEY AUTO_INCREMENT,
    title     VARCHAR(200),
    embedding VECTOR(128)        -- 128 维向量字段
) ENGINE=InnoDB;

企业版

CREATE TABLE articles (
    id        INT PRIMARY KEY AUTO_INCREMENT,
    title     VARCHAR(200),
    embedding VECTOR(128)        -- 128 维向量字段
) ENGINE=InnoDB
PARTITION BY KEY(id);

创建向量索引

  • 方式一:建表时直接创建。

    标准版

    CREATE TABLE articles (
        id        INT PRIMARY KEY AUTO_INCREMENT,
        title     VARCHAR(200),
        embedding VECTOR(128),
        VECTOR INDEX vi (embedding) M=6 DISTANCE=EUCLIDEAN
    ) ENGINE=InnoDB;

    企业版

    CREATE TABLE articles (
        id        INT PRIMARY KEY AUTO_INCREMENT,
        title     VARCHAR(200),
        embedding VECTOR(128),
        VECTOR INDEX vi (embedding) M=6 DISTANCE=EUCLIDEAN
    ) ENGINE=InnoDB
    PARTITION BY KEY(id);
  • 方式二:ALTER TABLE追加。

    ALTER TABLE articles ADD VECTOR INDEX vi (embedding) M=16 DISTANCE=COSINE;
  • 方式三:CREATE VECTOR INDEX。

    -- 使用默认参数 M=6, DISTANCE=EUCLIDEAN
    CREATE VECTOR INDEX vi ON articles (embedding);

索引参数说明

参数

含义

选型建议

M

每个节点在图中的最大邻居连接数。M 越大,索引占用空间越大、写入越慢,但搜索精度越高。

  • 取值范围:[3, 200]

  • 默认值:6

  • 低延迟场景用 3~6

  • 高精度场景用 12~16

  • 极端精度需求用 32+

DISTANCE

距离度量函数。EUCLIDEAN 衡量绝对空间距离,COSINE 衡量方向相似度。取值范围:

  • EUCLIDEAN(默认):欧氏距离

  • COSINE:余弦距离

  • 文本嵌入/NLP 推荐 COSINE

  • 图像特征/空间坐标推荐 EUCLIDEAN

查看向量索引

说明

向量索引不会出现在SHOW INDEX FROM <表名>的结果中,请使用SHOW CREATE TABLE查看。

-- 查看索引定义(向量索引以 VECTOR KEY 形式展示)
SHOW CREATE TABLE articles;

返回示例:

CREATE TABLE `articles` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(200) DEFAULT NULL,
  `embedding` vector(128) DEFAULT NULL,
  PRIMARY KEY (`id`),
  VECTOR INDEX `vi`(`embedding`) M=16 DISTANCE=COSINE
) ENGINE = InnoDB

删除向量索引

-- 删除向量索引
ALTER TABLE articles DROP INDEX vi;

写入与修改向量数据

您使用VEC_FROMTEXT()将字符串格式的向量转为内部存储格式。

  • 单行插入

    INSERT INTO articles (title, embedding) VALUES
      ('深度学习入门', VEC_FROMTEXT('[0.12, 0.34, 0.56, ...]'));
  • 批量插入

    INSERT INTO articles (title, embedding) VALUES
      ('文章A', VEC_FROMTEXT('[0.1, 0.2, 0.3, 0.4, 0.5]')),
      ('文章B', VEC_FROMTEXT('[0.5, 0.4, 0.3, 0.2, 0.1]'));
  • 更新向量字段(索引自动同步更新)

    UPDATE articles SET embedding = VEC_FROMTEXT('[0.9, 0.8, ...]') WHERE id = 1;
  • 删除行(索引自动同步清理)

    DELETE FROM articles WHERE id = 1;

向量检索

  • 标准检索模式为ORDER BY VEC_DISTANCE(...) LIMIT N

    -- 找出与目标向量最相似的 10 条记录
    SELECT id, title,
           VEC_DISTANCE(embedding, VEC_FROMTEXT('[0.1, 0.2, 0.3, 0.4, 0.5]')) AS distance
    FROM articles
    ORDER BY distance
    LIMIT 10;

    返回示例:

    +----+--------------+----------+------------------------+
    | id | name         | category | distance               |
    +----+--------------+----------+------------------------+
    |  2 | 降噪头戴耳机   | 数码     | 0.005887877200042468    |
    |  1 | 无线蓝牙耳机   | 数码     | 0.006059869516314431    |
    |  3 | 运动蓝牙耳机   | 运动     | 0.09631679001555782     |
    +----+--------------+----------+------------------------+

    优化器行为说明:

    • 优化器检测到 ORDER BY VEC_DISTANCE(...) LIMIT N 模式后,会基于代价自动选择向量索引。

    • 查询必须带 LIMIT 子句,否则不会使用向量索引。

    • LIMIT 过大(超过表行数的 1/4),优化器会回退为全表扫描。若大表查询意外回退,可通过 FORCE INDEX(向量索引名) 强制使用向量索引。

  • 使用Hint强制指定索引:

    -- 强制使用向量索引
    SELECT * FROM articles FORCE INDEX(vi)
    ORDER BY VEC_DISTANCE_EUCLIDEAN(embedding, VEC_FROMTEXT('[0.1, 0.2, 0.3, 0.4, 0.5]'))
    LIMIT 10;
    
    -- 强制全表扫描(精确计算,用于验证召回率)
    SELECT * FROM articles FORCE INDEX(PRIMARY)
    ORDER BY VEC_DISTANCE_EUCLIDEAN(embedding, VEC_FROMTEXT('[0.1, 0.2, 0.3, 0.4, 0.5]'))
    LIMIT 10;
  • 通过 EXPLAIN可确认是否使用了向量索引(命中时 key 列显示向量索引名):

    EXPLAIN SELECT * FROM articles
    ORDER BY VEC_DISTANCE(embedding, VEC_FROMTEXT('[0.1, 0.2, 0.3, 0.4, 0.5]'))
    LIMIT 10;
    说明

    PolarDB-X 使用分布式执行计划格式。命中向量索引时,physicalPlan中的key字段会显示向量索引名(如vi_embedding)。当表数据量较小时(如不足数百行),优化器可能选择全表扫描(key:null)。

向量函数

函数

等价别名

说明

VEC_FROMTEXT(str)

-

'[1.0, 2.0, 3.0]' 格式字符串转为向量

VEC_TOTEXT(vec)

-

将向量转回可读字符串

VEC_DISTANCE(v1, v2)

-

计算两向量距离。若 v1 为带索引列,自动采用该索引的距离类型

VEC_DISTANCE_EUCLIDEAN(v1, v2)

-

显式计算欧氏距离(L2)

VEC_DISTANCE_COSINE(v1, v2)

-

显式计算余弦距离(1 − 余弦相似度)

说明

日常查询推荐使用VEC_DISTANCE(),写法最简洁,且会自动匹配索引的距离类型。COSINE 距离返回的是1 − 余弦相似度,值越小表示越相似,与EUCLIDEAN方向一致,均使用ORDER BY distance升序。

系统变量与参数调优

变量名

作用域

说明

vidx_disabled

GLOBAL

向量索引功能总开关,修改后需重连生效。

  • ON(默认):关闭

  • OFF:开启

vidx_default_distance

SESSION

创建索引未指定DISTANCE时的默认距离类型。

  • EUCLIDEAN(默认):欧氏距离

  • COSINE:余弦距离

说明

仅可通过控制台参数设置页面修改,不支持SQL SET 命令。

vidx_hnsw_default_m

SESSION

创建索引未指定M(每个节点在图中的最大邻居连接数)时的默认值。

  • 取值范围:[3, 200]

  • 默认值:6

说明

仅可通过控制台参数设置页面修改,不支持SQL SET 命令。

vidx_hnsw_ef_search

SESSION

搜索时的候选集大小,越大精度越高但越慢,该值不会小于LIMIT。

  • 取值范围:[1, 10000]

  • 默认值:20

vidx_hnsw_cache_size

GLOBAL

单个向量索引的内存缓存上限。

  • 取值范围:[1 MB, ULLONG_MAX]

  • 默认值:16 MB

说明

仅可通过控制台参数设置页面修改,不支持SQL SET 命令。

ef_search 选型指南

ef_search

预期召回率

适用场景

10

~85%

低延迟优先,允许少量漏检

20(默认)

~92%

平衡精度与速度

50~100

~97%

高精度场景

200+

~99%+

接近暴力检索

调优示例

-- 提高搜索精度(牺牲一些延迟)
SET SESSION vidx_hnsw_ef_search = 100;

-- 降低延迟(牺牲一些精度)
SET SESSION vidx_hnsw_ef_search = 10;

监控与运维

您通过以下命令查看向量索引运行状态:

SHOW GLOBAL STATUS LIKE 'Vidx%';

返回示例:

+----------------------------------+----------+
| Variable_name                    | Value    |
+----------------------------------+----------+
| Vidx_cache_usage                 | 1048576  |
| Vidx_insert_count                | 5        |
| Vidx_load_node_hits              | 14       |
| Vidx_load_node_misses            | 10       |
| Vidx_load_vec_hits               | 6        |
| Vidx_load_vec_misses             | 6        |
| Vidx_query_count                 | 1        |
| Vidx_update_count                | 0        |
| ...                              | ...      |
+----------------------------------+----------+

常用监控指标

状态变量

含义

Vidx_query_count

向量查询总次数

Vidx_insert_count / Vidx_update_count

向量插入 / 更新总次数

Vidx_load_node_hits / Vidx_load_node_misses

图节点缓存命中 / 未命中次数

Vidx_load_vec_hits / Vidx_load_vec_misses

向量数据缓存命中 / 未命中次数

Vidx_cache_usage

当前缓存内存使用量(字节)

运维建议

  • 缓存命中率 = (Vidx_load_node_hits + Vidx_load_vec_hits)/(Vidx_load_node_hits + Vidx_load_node_misses + Vidx_load_vec_hits + Vidx_load_vec_misses,若低于 90%,可适当调大vidx_hnsw_cache_size

  • 定期执行 OPTIMIZE TABLE 可清理因更新/删除产生的冗余节点,控制空间增长。

  • 高精度需求时优先调大 vidx_hnsw_ef_search,并保证其不小于查询的 LIMIT

端到端示例

以下示例演示一个“商品语义搜索”完整流程:

  1. 开启功能

    SET GLOBAL vidx_disabled = OFF;
  2. 创建表并定义5维向量字段

    标准版

    CREATE TABLE products (
        id        INT PRIMARY KEY AUTO_INCREMENT,
        name      VARCHAR(100) NOT NULL,
        category  VARCHAR(50),
        embedding VECTOR(5)
    ) ENGINE=InnoDB;

    企业版

    CREATE TABLE products (
        id        INT PRIMARY KEY AUTO_INCREMENT,
        name      VARCHAR(100) NOT NULL,
        category  VARCHAR(50),
        embedding VECTOR(5)
    ) ENGINE=InnoDB
    PARTITION BY KEY(id);
  3. 创建向量索引(余弦距离)

    ALTER TABLE products ADD VECTOR INDEX vi_embedding (embedding) M=6 DISTANCE=COSINE;
  4. 写入商品数据

    INSERT INTO products (name, category, embedding) VALUES
      ('无线蓝牙耳机', '数码', VEC_FROMTEXT('[0.8, 0.1, 0.3, 0.5, 0.2]')),
      ('降噪头戴耳机', '数码', VEC_FROMTEXT('[0.7, 0.2, 0.4, 0.6, 0.1]')),
      ('运动蓝牙耳机', '运动', VEC_FROMTEXT('[0.6, 0.5, 0.3, 0.4, 0.3]')),
      ('智能手表', '数码', VEC_FROMTEXT('[0.3, 0.7, 0.2, 0.8, 0.1]'));
  5. 检索与“蓝牙耳机”最相似的3个商品

    SELECT id, name, category,
     VEC_DISTANCE(embedding, VEC_FROMTEXT('[0.75, 0.15, 0.35, 0.55, 0.15]')) AS distance
    FROM products
    ORDER BY distance
    LIMIT 3;

    返回示例:

    +----+--------------+----------+------------------------+
    | id | name         | category | distance               |
    +----+--------------+----------+------------------------+
    |  2 | 降噪头戴耳机   | 数码      | 0.005887877200042468   |
    |  1 | 无线蓝牙耳机   | 数码      | 0.006059869516314431   |
    |  3 | 运动蓝牙耳机   | 运动      | 0.09631679001555782    |
    +----+--------------+----------+------------------------+

常见问题

  • 如何确认实例是否支持并已开启向量索引?

    确认实例存储节点版本不低于V2.6.0.8.4.21-20260605,并通过以下命令确认功能已开启,返回OFF表示已开启。

    SHOW GLOBAL VARIABLES LIKE 'vidx_disabled';

    返回示例:

    +-----------------+-------+
    | Variable_name   | Value |
    +-----------------+-------+
    | vidx_disabled   | OFF   |
    +-----------------+-------+
  • 为什么向量检索没有走索引?

    请依次确认:

    1. vidx_disabled = OFF 且已重新建立连接。

    2. SQL 包含 ORDER BY VEC_DISTANCE(...) LIMIT N

    3. LIMIT 值未超过表行数的 1/4。

    可通过 EXPLAIN 验证,命中时 key 列会显示向量索引名。

  • 检索召回率不达预期怎么办?

    可调大会话变量 vidx_hnsw_ef_search(如 50~100),或在建索引时增大 M(如 16)。可使用 FORCE INDEX(PRIMARY) 做全表精确检索作为对比基准。

  • 创建向量索引为什么比较慢?

    向量索引使用 COPY 算法构建,需要为存量数据逐条建立 HNSW 图结构,大表耗时较长,建议在业务低峰期执行。

  • 向量索引会增加多少存储和内存?

    • 存储:索引大小约为基表向量列大小的 1.5 倍。

    • 内存:由 vidx_hnsw_cache_size 控制单个索引的缓存上限。

    • 缓存:主要由行数、向量维度和 M 决定,可用以下经验公式估算(单位:字节):

      vidx_hnsw_cache_size ≈ 行数 × (维度 × 2 + M × 16 + 60)
      • 维度 × 2:向量经量化压缩后的大小(每维 2 字节)。

      • M × 16:图节点邻居连接的开销。

      • 60:节点对象等固定开销。

      估算示例:

      行数

      维度

      M

      建议缓存

      100 万

      128

      6

      ≈ 700 MB

      100 万

      768

      16

      ≈ 1.8 GB

      1000 万

      128

      6

      ≈ 7 GB

    说明

    缓存超过上限后会触发整体重建、影响查询性能。建议在估算值基础上适当上调;若监控发现缓存命中率偏低,可再调大。

  • 向量索引支持主备复制和高可用吗?

    支持。向量数据的写入与基表在同一事务内同步,通过Binlog复制到备库,主备数据保持一致,同时支持XA事务。在企业版(分布式)下,向量索引还支持分布式事务,跨分片的向量数据写入与检索可在分布式事务中保证一致性。