MySQL JSON路径表达式返回NULL主因是路径语法错误:大小写、引号、括号嵌套或数组下标(须用[0])偏差均导致静默失败;键名含空格需双引号;->自动解包,保留引号须用->>。

MySQL JSON路径表达式里为什么总是返回 NULL
不是 JSON 字段本身为空,而是路径写错了——MySQL 的 JSON_EXTRACT 和 -> 操作符对路径语法极其敏感,大小写、引号、括号嵌套稍有偏差就静默返回 NULL。
- 数组下标必须用
[0],不能写成.0或[1](MySQL 从 0 开始索引) - 键名含空格或特殊字符时,必须用双引号包裹:正确是
"user name",错误是user name -
->操作符会自动解包字符串,想保留引号得用->>;反之若原值是数字但路径错配,也可能转成NULL - 嵌套对象路径中,
$.data.items[0].name是合法的,但$.data.items.[0].name(多了一个点)就会失败
JSON_CONTAINS 和 JSON_OVERLAPS 性能差异在哪
二者都走不了索引,但底层行为不同:前者逐字段递归比对,后者只检查顶层键值是否重叠,所以 JSON_OVERLAPS 更快,但适用面窄得多。
-
JSON_CONTAINS(@json, '"admin"', '$.roles')会完整解析$.roles数组并逐个匹配字符串,哪怕数组有 100 个元素也全扫一遍 -
JSON_OVERLAPS('["admin","user"]', @json->'$.roles')只比较两个 JSON 数组的交集,不展开嵌套结构,也不支持路径内嵌查询 - 两者都不能利用函数索引加速,除非你提前把关键字段抽成普通列(比如
role_list VARCHAR(255)),再建前缀索引
JSON_SET/JSON_REPLACE/JSON_INSERT 的行为边界
名字看着像,实际逻辑完全不同:一个改值、一个只更新已有键、一个只新增缺失键——混用会导致字段“消失”或“被静默忽略”。
-
JSON_SET(json_col, '$.status', 'done'):无论status存不存在,都设值;路径不存在时会创建整条路径 -
JSON_REPLACE(json_col, '$.status', 'done'):仅当status已存在才替换,否则整个操作无效,返回原 JSON -
JSON_INSERT(json_col, '$.status', 'done'):仅当status不存在才插入,已存在则不改动 - 三者都不支持通配符路径(如
$.*.id),也不能批量操作多个路径,一次只能处理一个键
JSON 字段能不能加索引?怎么加才真正有效
不能直接给 JSON 列建索引,但可以基于路径表达式建生成列 + 普通索引——不过要注意 MySQL 版本限制和类型推导陷阱。
- MySQL 5.7+ 支持虚拟列:
ALTER TABLE users ADD status VARCHAR(20) AS (json_unquote(json_extract(data, '$.status'))) STORED; - 必须用
json_unquote()去掉外层引号,否则索引值带双引号,WHERE 查询时status = 'active'就无法命中 - 生成列类型要和实际值一致:如果
$.score是数字,就该用DECIMAL而非VARCHAR,否则排序和范围查询失效 - MySQL 8.0.17+ 才支持在虚拟列上建函数索引,老版本只能用
STORED列 + 普通 B-tree 索引
JSON 路径解析不是黑盒,它依赖精确的语法和显式的类型转换。最容易被忽略的是:所有路径操作都默认按 UTF8MB4 解析,一旦源 JSON 里混入非标准编码或控制字符,JSON_VALID() 都可能返回 false,但错误信息只显示 Invalid JSON text,没具体位置。










