MySQL中JSON_EXTRACT路径必须以$开头,否则返回NULL;→>>可简化取值但无索引优化,频繁查询应结构化拆表或建生成列索引。

MySQL 用 JSON_EXTRACT 取嵌套 JSON 数据,路径写错不报错、只返回 NULL,这是最常踩的坑。
路径必须以 $ 开头,对象用点、数组用方括号
MySQL 不接受省略根符号或用斜杠的写法(比如 '/name' 或 'name'),必须从 $ 开始。嵌套层级越深,路径越容易漏掉点或括号。
-
$.user.profile.name→ 正确:三层嵌套对象 -
$.items[0].price→ 正确:取第一个数组元素的price字段 -
$.items[1]→ 错误:如果数组只有 1 个元素(下标 0),这个就返回NULL,但不会提示越界 -
$.data."user-id"→ 正确:键名含短横线,必须加双引号
用 ->> 比 JSON_EXTRACT 更省事,但版本要 ≥ 5.7.13
->> 是语法糖,等价于 JSON_UNQUOTE(JSON_EXTRACT(...)),直接返回去引号后的字符串值,不用再套函数。
-
SELECT data ->> '$.name' FROM t→ 得到纯文本Alice -
SELECT JSON_EXTRACT(data, '$.name')→ 得到带双引号的"Alice" - 对数字或布尔值,
->>也会转成对应类型字符串(true→"true"),不是原生类型 - 如果字段本身是
NULL或 JSON 格式非法,->>同样返回NULL
WHERE 条件里直接用 ->> 查嵌套字段,性能很差
MySQL 对 JSON 字段不支持普通索引加速路径查询。每次执行 WHERE data ->> '$.status' = 'active',都会全表扫描并逐行解析 JSON。
- 临时解法:加
JSON_VALID(data)过滤,避免无效 JSON 干扰结果 - 长期解法:建生成列 + 索引,例如:
ALTER TABLE t ADD COLUMN status_text VARCHAR(20) GENERATED ALWAYS AS (data ->> '$.status') STORED;<br>CREATE INDEX idx_status ON t(status_text);
- 注意:生成列必须是
STORED才能建索引;VIRTUAL列不行
数组里取多个元素?别硬写 [0], [1],用 JSON_TABLE(MySQL 8.0+)
想把 $.items 这种数组展开成多行记录,用一堆 JSON_EXTRACT(..., '$.items[0]') + UNION 不现实,也难维护。
- MySQL 8.0 起推荐用
JSON_TABLE,它能把 JSON 数组“炸开”成关系表: SELECT jt.id, jt.price<br>FROM t,<br> JSON_TABLE(t.data, '$.items[*]'<br> COLUMNS (<br> id INT PATH '$.id',<br> price DECIMAL(10,2) PATH '$.price'<br> )<br> ) AS jt;
- 路径里的
[*]表示遍历所有数组元素,比手写下标健壮得多
真正麻烦的不是语法,而是 JSON 字段一旦进 WHERE 或 JOIN,就基本告别索引优化;嵌套越深、数组越长,解析开销越大。线上表如果频繁查 JSON 内部字段,优先考虑结构化拆表,而不是靠路径表达式硬扛。











