MySQL 8.0 “复杂类型”实战
文章目录
- 1. 课程目标
- 2. 环境准备
- 2.1 MySQL ≥ 8.0.17(多值索引最低版本)
- 2.2 客户端采用Navicat
- 2.3 创建专用库,避免污染业务数据
- 3. 场景:电商商品标签
- 4. 建表[无索引版本]
- 4.1 创建表结构
- 4.2 灌一批演示数据
- 5. 无索引查询
- 5.1 提出需求
- 5.2 完成任务
- 5.3 分析查询语句的执行效率
- 6. 函数索引(单键)
- 6.1 提出任务
- 6.1 完成任务
- 6.3 分析查询语句的执行效率
- 7. 多值索引(JSON 数组)
- 7.1 重建多值索引表
- 7.2 插入样例数据
- 7.3 尝试两种查询写法
- 7.3.1 使用 MEMBER OF进行查询
- 7.3.2 使用JSON_CONTAINS进行查询
- 7.4 验证索引生效
- 8. 组合过滤 + 回表
- 8.1 提出需求
- 8.2 完成任务
- 9. 实战小结
1. 课程目标
- 用 JSON 存“数组/结构体/Map”
- 用“多值索引”给 JSON 数组加速
- 用“函数索引”给 JSON 字段子键加速
- 对比执行计划,看到索引真实生效
2. 环境准备
2.1 MySQL ≥ 8.0.17(多值索引最低版本)
- 当前MySQL版本:8.0.43
2.2 客户端采用Navicat
- 当前Navicat版本15
2.3 创建专用库,避免污染业务数据
- 执行命令:
CREATE DATABASE demo_json CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
- 打开
demo_json
数据库
3. 场景:电商商品标签
- 每个商品有一组动态标签(数组)
- 有一组动态销售属性(结构体/Map)
- 要按“标签”和“属性子键”做高速查询
4. 建表[无索引版本]
4.1 创建表结构
-
执行命令
CREATE TABLE sku_raw(sku_id BIGINT PRIMARY KEY,sku_name VARCHAR(100),tag_list JSON, prop_map JSON );
-
纯数组示例:
["spring","summer", "autumn", "winter"]
-
纯Map示例,
{"brand":"Nike", "color":"red","size":"XL"}
-
查看结果
4.2 灌一批演示数据
-
执行命令
INSERT INTO sku_raw VALUES (1,'iPhone 15', '["new", "hot", "electronic"]', '{"color":"black","storage":"256G"}'), (2,'连衣裙', '["summer", "new"]', '{"color":"red","size":"M"}'), (3,'风扇', '["hot", "summer"]', '{"color":"white","power":"30W"}'), (4,'MacBook', '["electronic", "new"]', '{"color":"gray","ram":"16G"}');
-
查看结果
-
查看
sku_raw
表记录
5. 无索引查询
5.1 提出需求
- 找出所有带
"summer"
标签的商品
5.2 完成任务
- 执行命令
SELECT sku_id, sku_nameFROM sku_rawWHERE JSON_CONTAINS(tag_list, '"summer"');
- 查看结果
5.3 分析查询语句的执行效率
- 执行命令:
EXPLAIN SELECT sku_id, sku_name FROM sku_raw WHERE JSON_CONTAINS(tag_list, '"summer"');
,分析查询语句的执行效率
- EXPLAIN 结果详解
- 性能瓶颈:全表扫描 + 函数计算
- 因为 tag_list 是一个 JSON 字段,且没有为它建立合适的索引
- JSON_CONTAINS() 是一个函数,MySQL 无法直接通过它走索引
- 只能对表中的每一行都执行一次 JSON_CONTAINS(tag_list, ‘“summer”’)
- 导致效率极低,尤其当表很大时(比如几十万、几百万行),会非常慢
6. 函数索引(单键)
6.1 提出任务
- 给
prop_map.color
建索引
6.1 完成任务
- 执行命令
ALTER TABLE sku_rawADD COLUMN gen_color CHAR(20)GENERATED ALWAYS AS (JSON_UNQUOTE(prop_map->'$.color')) STORED,ADD INDEX idx_color(gen_color);
- 语句说明
- 查看结果
- 查看
sku_raw
表记录
6.3 分析查询语句的执行效率
- 执行命令:
EXPLAIN SELECT * FROM sku_raw WHERE gen_color='red'
,分析查询语句的执行效率
- EXPLAIN 结果详解
- 总结:这条查询表现如何?
- 结论:这是一个高性能的查询!因为创建了生成列
gen_color
;为它建立了索引idx_color
;查询条件正好匹配该索引字段。MySQL可以直接通过索引快速定位到gen_color = 'red'
的记录,而不需要扫描整张表或解析JSON。
7. 多值索引(JSON 数组)
7.1 重建多值索引表
- 一张带多值索引的表(8.0.17+ 语法)
- 执行命令
CREATE TABLE sku(sku_id BIGINT PRIMARY KEY,sku_name VARCHAR(100),tag_list JSON,prop_map JSON, INDEX idx_tag_list( (CAST(tag_list AS CHAR(20) ARRAY)) ) );
- 查看结果
7.2 插入样例数据
-
执行命令
INSERT INTO sku VALUES (1,'iPhone 15', '["new", "hot", "electronic"]', '{"color":"black","storage":"256G"}'), (2,'连衣裙', '["summer", "new"]', '{"color":"red","size":"M"}'), (3,'风扇', '["hot", "summer"]', '{"color":"white","power":"30W"}'), (4,'MacBook', '["electronic", "new"]', '{"color":"gray","ram":"16G"}');
-
查看结果
7.3 尝试两种查询写法
7.3.1 使用 MEMBER OF进行查询
- 执行命令
SELECT sku_id, sku_nameFROM skuWHERE 'summer' MEMBER OF(tag_list);
- 查看结果
7.3.2 使用JSON_CONTAINS进行查询
- 执行命令
SELECT sku_id, sku_nameFROM skuWHERE JSON_CONTAINS(tag_list, '"summer"');
- 查看结果
7.4 验证索引生效
- 执行命令:
EXPLAIN SELECT sku_id, sku_name FROM sku WHERE 'summer' MEMBER OF(tag_list)
- EXPLAIN结果解释
8. 组合过滤 + 回表
8.1 提出需求
- 标签含
“new”
且color=red
8.2 完成任务
-
执行命令
SELECT a.sku_id, a.sku_nameFROM sku aWHERE 'new' MEMBER OF(a.tag_list)AND JSON_UNQUOTE(a.prop_map->'$.color')='red';
-
查看结果
-
执行命令
EXPLAIN SELECT a.sku_id, a.sku_nameFROM sku aWHERE 'new' MEMBER OF(a.tag_list)AND JSON_UNQUOTE(a.prop_map->'$.color')='red';
-
查看结果
-
- EXPLAIN结果解释
- EXPLAIN结果解释
9. 实战小结
- 本文通过电商商品标签场景,系统演示了MySQL 8.0+中JSON字段的高效查询优化方案。针对JSON数组查询性能瓶颈,采用多值索引(
CAST(... AS ARRAY)
)结合MEMBER OF
语法,显著提升标签匹配效率;对于JSON对象中的特定字段查询,利用生成列+函数索引实现对color
等属性的快速检索。执行计划验证表明,两种索引均能有效避免全表扫描,大幅降低查询成本。组合查询虽涉及回表,但核心过滤条件仍可走索引,整体性能可控。实践表明,合理使用多值索引与函数索引,可充分发挥JSON灵活性与查询高效性的双重优势。