MySQL 的 JSON 能力
MySQL 5.7 起提供原生 JSON 数据类型与一套配套函数:JSON_EXTRACT 按路径取值,箭头语法 -> 与 ->> 是其简写(后者去掉结果中的引号),JSON_SET 用于更新路径上的值,JSON_TABLE 能把 JSON 展开成行。JSON 列在写入时会校验格式,但没有索引能力,高频过滤的字段需要通过生成列或函数索引来加速。
基本信息
| 适用平台 | MySQL 5.7+(JSON_TABLE 与函数索引需 8.0) |
|---|---|
| 常用函数 | JSON_EXTRACT、JSON_SET、JSON_UNQUOTE、JSON_TABLE |
| 箭头语法 | -> 返回 JSON 值,->> 返回去引号文本 |
| 索引方式 | STORED 生成列加索引,或 8.0 的函数索引 |
| 存储校验 | JSON 列写入时校验格式,不合法直接报错 |
典型使用场景
- 属性表模式:商品或用户的可变属性放在 JSON 列,避免频繁加字段
- 日志与事件记录:结构不固定的附加信息统一存 JSON
- 配置项存储:不同租户的差异化配置放在一列里
- 接口响应缓存:把上游返回的结构化数据原样落库便于追溯
- JSON 数组展开成行,用于统计某个字段的取值分布
常用示例
常用示例
-- 提取字段:->> 返回去引号的文本,便于字符串比较
SELECT JSON_EXTRACT(attrs, '$.color') FROM products;
SELECT attrs->>'$.color' AS color FROM products;
-- 更新 JSON 路径上的值
UPDATE products SET attrs = JSON_SET(attrs, '$.stock', 10) WHERE id = 1;
-- 按 JSON 字段过滤(走索引需要生成列)
SELECT id FROM products WHERE attrs->>'$.color' = 'red';
-- 展开数组为行,统计取值分布
SELECT jt.tag, COUNT(*) FROM products,
JSON_TABLE(products.attrs, '$.tags[*]' COLUMNS (tag VARCHAR(32) PATH '$')) AS jt
GROUP BY jt.tag;生成列加索引加速
生成列加索引加速
-- 把高频过滤的 JSON 字段落成 STORED 生成列
ALTER TABLE products
ADD COLUMN color VARCHAR(32) GENERATED ALWAYS AS (attrs->>'$.color') STORED,
ADD INDEX idx_color (color);
-- 之后查询可命中索引
SELECT id FROM products WHERE color = 'red';
-- 8.0 也可用函数索引
ALTER TABLE products ADD INDEX idx_color_fn ((attrs->>'$.color'));常用函数与选项
| 函数 | 作用 | 注意 |
|---|---|---|
| JSON_EXTRACT | 按路径提取值 | 返回 JSON 形式,字符串带引号 |
| -> 与 ->> | 取值简写 | 后者去引号,比较文本时选它 |
| JSON_SET | 更新或新增路径值 | 路径不存在则新增 |
| JSON_UNQUOTE | 去掉结果中的引号 | 等价于 ->> 的效果 |
| JSON_TABLE | 把 JSON 展开为行(8.0) | 适合数组统计 |
| GENERATED ... STORED | 落成真实列以便建索引 | VIRTUAL 也可建索引但行为略有差异 |
直接对 JSON 表达式过滤走不了普通索引:高频查询字段应通过 STORED 生成列或 8.0 的函数索引来支撑,这是官方的推荐做法。
JSON 列不适合承载强约束数据:类型、长度与唯一性都无法像普通列那样约束,把订单金额这类关键字段放进去会给后续校验与统计带来麻烦。