MySQL 5.7 新增了一个 JSON 类型,它的设计目标不是简单地把 JSON 当作 TEXT 存储,而是采用内部二进制格式保存 JSON 文档,从而支持结构化访问、校验和部分索引能力。
PS: 8.0 增加了 JSON_TABLE()、JSON_VALUE()、JSON_OVERLAPS()、MEMBER OF()、JSON Schema 验证等能力,同时 JSON 索引和查询能力也进一步增强。
CREATE TABLE users (
id BIGINT PRIMARY KEY,
profile JSON
);
写入时 MySQL 会验证数据是否为合法 JSON,因此,JSON 列相比 TEXT 的一个重要优势是数据库层面保证数据格式合法。
查询
查询指定 JSON 字段:
SELECT JSON_EXTRACT(profile, '$.name') FROM users;
同时支持 -> 和 ->> 操作符:
SELECT profile->'$.name';
SELECT profile->>'$.name';
其中 -> 返回 JSON 值,->> 返回去除 JSON 引号后的字符串。
修改
| 函数 | 作用 |
|---|---|
JSON_SET() |
存在则修改,不存在则新增 |
JSON_INSERT() |
只新增,不覆盖已有值 |
JSON_REPLACE() |
只修改已有值 |
JSON_REMOVE() |
删除指定路径 |
JSON_ARRAY_APPEND() |
向数组追加元素 |
JSON_ARRAY_INSERT() |
向数组指定位置插入元素 |
例如:
UPDATE users
SET profile = JSON_SET(profile, '$.age', 37)
WHERE id = 1;
索引
MySQL 5.7 支持 JSON_CONTAINS()、JSON_CONTAINS_PATH()、JSON_SEARCH() 等查询函数。
不支持直接给 JSON 列建立普通 B-Tree 索引。常见做法是通过生成列提取需要查询的字段,再对生成列建立索引:
ALTER TABLE users
ADD COLUMN name VARCHAR(100) GENERATED ALWAYS AS (profile->>'$.name'),
ADD INDEX idx_name (name);
这也是 MySQL 5.7 JSON 应用中非常重要的性能实践。