MySQL JSON路径必须以$开头,否则JSON_EXTRACT()或->静默返回NULL;->返回JSON类型,->>返回原生类型;数组下标从0开始,越界或字段缺失均返回NULL;WHERE中直接用JSON函数会导致全表扫描。

路径必须以 $ 开头,否则一律返回 NULL
MySQL 对 JSON 路径语法极其严格:任何不以 $ 开头的路径(比如 .user.name、items[0].price、/user/name)都会让 JSON_EXTRACT() 或 -> 静默返回 NULL,且不报错。这是查出来全是 NULL 却找不到原因的最常见根源。
正确写法只有一种模式:$ 后接点号或方括号层级展开:
-
$.name→ 顶层字段 -
$.address.city→ 嵌套对象字段 -
$.hobbies[0]→ 数组第一个元素 -
$.users[1].profile.name→ 多层嵌套 + 数组索引 -
$."user-id"→ 键名含短横线,必须加双引号
-> 和 ->> 的类型差异直接影响 WHERE 和 ORDER BY 行为
用 -> 提取的结果仍是 JSON 类型(带双引号),而 ->> 会自动调用 JSON_UNQUOTE(),返回原生字符串或数字文本。这个区别在条件查询和排序时会直接导致逻辑失效或性能退化。
例如:
-
SELECT * FROM t WHERE data->'$.status' = 'active'→ 实际比较的是"active"(JSON 字符串)和active(字符串字面量),永远不等 -
SELECT * FROM t WHERE data->>'$.status' = 'active'→ 正确匹配 -
ORDER BY data->'$.score'→ 按 JSON 字符串排序("9" > "10"),不是数值序 -
ORDER BY data->>'$.score'→ 仍按字符串排;若要数值序,需再转CAST(data->>'$.score' AS SIGNED)
数组下标从 0 开始,越界或字段缺失都静默返回 NULL
MySQL 不会提示“索引超出范围”或“键不存在”,而是统一返回 NULL。这意味着你写 $.items[5],哪怕数组只有 3 个元素,也不会报错,只是得不到值。
实用建议:
- 先确认数组长度:
JSON_LENGTH(data, '$.items') - 用
COALESCE(JSON_EXTRACT(data, '$.items[0].name'), 'N/A')避免空值干扰业务逻辑 - 访问动态索引时(如循环处理),别硬写死下标,优先考虑用
JSON_TABLE()(MySQL 8.0+)或应用层解析 - 嵌套数组路径不能跳级,
$.items[*].price是非法的(MySQL 5.7 不支持通配符),必须明确指定索引,如$.items[0].price
WHERE 中直接用 JSON 函数会导致全表扫描
WHERE data->>'$.status' = 'active' 这类写法无法走索引——因为表达式右侧是函数计算结果,MySQL 5.7 无法对 JSON 字段做前缀索引或函数索引(直到 8.0.13 才支持函数索引)。
真正可落地的优化方式只有两种:
- 建生成列(generated column)+ 普通索引:
ALTER TABLE t ADD COLUMN status VARCHAR(20) AS (data->>'$.status') STORED;<br>CREATE INDEX idx_status ON t(status);
- 用
JSON_CONTAINS()配合 JSON 类型字段的原生索引(仅适用于查找是否存在某个键/值,不适用于精确匹配或范围查询)
没有生成列或索引支撑时,千万避免在大表 WHERE 里直接调用 JSON_EXTRACT 或 ->> —— 看似一行 SQL 很简洁,实际是隐性性能炸弹。


















