多值索引是什么
多值索引是 MySQL 8.0.17 引入的特性:为 JSON 数组的每个元素各建一条索引记录,让「数组包含某值」这类判断也能走索引,而不是把整列展开之后再过滤。
基本信息
| 版本 | MySQL 8.0.17 起支持 |
|---|---|
| 语法 | 在 CAST(表达式 AS 类型 ARRAY) 上建索引 |
| 元素类型 | CAST 目标类型要覆盖元素值域,可选 CHAR/SIGNED/UNSIGNED/DATE 等 |
| 可配合的条件 | MEMBER OF、JSON_CONTAINS、JSON_OVERLAPS 等 |
| 验证方式 | 用 EXPLAIN 确认命中多值索引 |
典型使用场景
- 商品标签数组的检索
- 用户兴趣标签匹配
- 订单里多商品 ID 的包含判断
- JSON 数组字段高频过滤时替代展开查询
- 评估是否值得把 JSON 拆成关联表
示例
示例
-- 在数组元素上建多值索引
ALTER TABLE products
ADD INDEX idx_tags ((CAST(tags -> '$.tags' AS CHAR(20) ARRAY)));
-- 可命中多值索引的写法
SELECT * FROM products
WHERE JSON_CONTAINS(tags -> '$.tags', '"book"');
SELECT * FROM products
WHERE 'book' MEMBER OF (tags -> '$.tags');
-- 检查是否命中
EXPLAIN SELECT * FROM products
WHERE 'book' MEMBER OF (tags -> '$.tags');条件与命中情况
| 条件写法 | 能否用多值索引 | 说明 |
|---|---|---|
| MEMBER OF | 可以 | 最直接的数组包含判断 |
| JSON_CONTAINS | 可以 | 表达式需与索引一致 |
| JSON_OVERLAPS | 可以 | 判断两个数组有交集 |
| 先展开再过滤 | 不适用 | 走的是展开后的行集 |
| JSON 列等值比较 | 不能 | 整体比较用不上数组索引 |
CAST 的目标类型要与数据匹配:元素超长会被截断、类型不符会匹配异常,建索引前先核对元素实际取值范围与长度。
多值索引只解决「包含」类判断:要按数组元素分组统计或排序,仍需要展开成行,或考虑拆成关联表。
多值索引可以与普通索引共存:只给高频的包含判断建多值索引,其余 JSON 查询仍走生成列或表达式索引,两套方案并不冲突。
同一 JSON 路径上重复建多种索引要谨慎:索引越多写入维护越重,先明确查询形态,再决定用多值索引还是生成列索引。