一、为什么 MySQL 要引入 JSON 字段?
在互联网业务中,经常会遇到以下情况:
- 字段属性不固定(如商品属性、用户画像标签等)
- 结构会随着业务变化而变化,不适合频繁修改表结构
- 希望兼顾查询能力和灵活性
MySQL 从 5.7 版本开始原生支持 JSON 类型,提供了结构化存储、自动校验、丰富查询函数等能力,用于解决传统 text/varchar 存储 JSON 的不足。
二、JSON 字段有哪些特点?
1. 存储格式是二进制(不是纯文本)
- MySQL 内部会将 JSON 数据解析为 binary JSON,查询更快。
- 插入时会进行 语法校验,不是合法 JSON 会报错。
2. 可索引,但有限制
MySQL 给 JSON 字段建立索引有两种方式:
方式 1:生成列(Generated Column)+ 索引
ALTER TABLE user
ADD COLUMN age_int INT GENERATED ALWAYS AS (json_extract(profile, '$.age')) STORED,
ADD INDEX idx_age(age_int);
这是最常见、最稳定的用法。
方式 2:MySQL 8.0 的功能索引(Functional Index)
CREATE INDEX idx_city
ON user ((json_unquote(json_extract(profile, '$.city'))));
三、JSON 字段常用操作
下面这些是最常用的 JSON 操作函数,建议掌握。
1. 插入/更新 JSON
INSERT INTO user(profile)
VALUES ('{"age": 20, "city": "Beijing"}');
部分修改 JSON(不需要整段覆盖):
UPDATE user
SET profile = JSON_SET(profile, '$.age', 21)
WHERE id = 1;
删除字段:
UPDATE user
SET profile = JSON_REMOVE(profile, '$.city')
WHERE id = 1;
四、如何查询 JSON 字段?
1. 查询某个键
SELECT JSON_EXTRACT(profile, '$.age') AS age
FROM user;
去掉引号的值(更常用):
SELECT JSON_UNQUOTE(JSON_EXTRACT(profile, '$.age')) AS age
FROM user;
2. 条件查询
一、为什么 MySQL 要引入 JSON 字段?
在互联网业务中,经常会遇到以下情况:
- 字段属性不固定(如商品属性、用户画像标签等)
- 结构会随着业务变化而变化,不适合频繁修改表结构
- 希望兼顾查询能力和灵活性
MySQL 从 5.7 版本开始原生支持 JSON 类型,提供了结构化存储、自动校验、丰富查询函数等能力,用于解决传统 text/varchar 存储 JSON 的不足。
二、JSON 字段有哪些特点?
1. 存储格式是二进制(不是纯文本)
- MySQL 内部会将 JSON 数据解析为 binary JSON,查询更快。
- 插入时会进行 语法校验,不是合法 JSON 会报错。
2. 可索引,但有限制
MySQL 给 JSON 字段建立索引有两种方式:
方式 1:生成列(Generated Column)+ 索引
ALTER TABLE user
ADD COLUMN age_int INT GENERATED ALWAYS AS (json_extract(profile, '$.age')) STORED,
ADD INDEX idx_age(age_int);
这是最常见、最稳定的用法。
方式 2:MySQL 8.0 的功能索引(Functional Index)
CREATE INDEX idx_city
ON user ((json_unquote(json_extract(profile, '$.city'))));
三、JSON 字段常用操作
下面这些是最常用的 JSON 操作函数,建议掌握。
1. 插入/更新 JSON
INSERT INTO user(profile)
VALUES ('{"age": 20, "city": "Beijing"}');
部分修改 JSON(不需要整段覆盖):
UPDATE user
SET profile = JSON_SET(profile, '$.age', 21)
WHERE id = 1;
删除字段:
UPDATE user
SET profile = JSON_REMOVE(profile, '$.city')
WHERE id = 1;
四、如何查询 JSON 字段?
1. 查询某个键
SELECT JSON_EXTRACT(profile, '$.age') AS age
FROM user;
去掉引号的值(更常用):
SELECT JSON_UNQUOTE(JSON_EXTRACT(profile, '$.age')) AS age
FROM user;
2. 条件查询
SELECT * FROM user
WHERE JSON_EXTRACT(profile, '$.city') = 'Beijing';
更推荐 UNQUOTE:
SELECT * FROM user
WHERE JSON_UNQUOTE(JSON_EXTRACT(profile, '$.city')) = 'Beijing';
五、JSON 数组处理
如果 JSON 字段是数组,如:
["tag1", "tag2", "tag3"]
判断数组是否包含某元素
SELECT *
FROM user
WHERE JSON_CONTAINS(tags, '"tag1"');
向数组追加元素
UPDATE user
SET tags = JSON_ARRAY_APPEND(tags, '$', 'tag4');
六、JSON 字段的适用场景
JSON 非万能,应根据场景使用。
适合用 JSON 的情况
- 字段结构不固定:商品自定义属性、用户扩展信息
- 读取频率高、写入频率低
- 查询灵活性要求高、不希望频繁修改表结构
不适合的情况
- 需要大量查询或排序的字段
- 需要建立复杂索引
- 数据结构稳定、本来就适合关系型
一句话总结:
JSON 适合“变化多、查询少”的场景;
常规字段适合“变化少、查询多”的场景。
七、JSON 字段的最佳实践
1. 能结构化的字段不要用 JSON
比如手机号、城市、性别、邮箱,这些都不应该放 JSON。
2. 为常用查询字段建立生成列索引
ALTER TABLE user
ADD COLUMN city VARCHAR(32) GENERATED ALWAYS AS (json_unquote(json_extract(profile, '$.city'))) STORED,
ADD INDEX idx_city(city);
3. 避免存太深的嵌套结构
深层 JSON 查询会变慢,能简单就简单。
八、总结
MySQL 的 JSON 字段是一个非常实用的工具,但并不是用来代替关系模型的。合理使用 JSON,可以让你的数据结构更灵活、开发效率更高。
记住两点即可:
- JSON 适合变化多、不适合大量查询。
- JSON 查询要配合“生成列 + 索引”实现高性能。