JSON_EXTRACT 返回带引号的 JSON 字符串,->> 是其语法糖并自动 JSON_UNQUOTE;前者适用于后续嵌套解析,后者用于直接比较或拼接;->> 仅 MySQL 5.7.13+ 支持。
json 字段的写法坑">
JSON_EXTRACT 和 ->> 的本质区别在哪
JSON_EXTRACT 返回的是 JSON 类型值(带引号、转义),而 ->> 是 JSON_EXTRACT 的语法糖,但会自动调用 JSON_UNQUOTE 去掉外层双引号并处理转义。这意味着:如果字段值是字符串,->> 给你纯文本,JSON_EXTRACT 给你带引号的 JSON 字符串。
常见错误现象:用 JSON_EXTRACT 取出一个字符串后直接和 'abc' 比较,结果永远不等——因为实际值是 "abc"(含引号)。
- 要比较或拼接时,优先用
->> - 要保留原始 JSON 结构(比如后续再嵌套解析),才用
JSON_EXTRACT -
->>在 MySQL 5.7.13+ 才支持;低版本只能用JSON_EXTRACT+JSON_UNQUOTE
嵌套路径写法:$ 后面不能漏掉 . 或 [*]
MySQL 的 JSON 路径表达式以 $ 开头,后面必须跟合法路径操作符。常见写错:把 $.data.user.name 写成 $data.user.name(漏 .),或把数组元素取法写成 $.items[0].id 却忘了 items 可能为 NULL 或非数组。
典型错误信息:Invalid path expression 或返回 NULL 却查不出原因。
- 路径中每个层级之间必须用
.连接,$后第一个点不能省 - 访问数组第 0 个元素:用
$[0](顶层数组)或$.list[0](字段内数组) - 不确定某层是否为数组?先用
JSON_TYPE(col->>'$.path')查类型,避免静默返回NULL - 路径含空格或特殊字符(如
first name):必须写成$.`first name`或$."first name"
NULL 安全提取:别让一层 null 把整个链路搞挂
JSON 路径是“短路”求值的:只要中间某层是 NULL 或不存在,整条表达式就返回 NULL,不会报错,但容易掩盖数据质量问题。
例如:data->>'$.user.profile.age' 在 user 为 NULL 时直接返回 NULL,你可能误以为 age 缺失,其实是 user 根本没存。
- 用
JSON_CONTAINS_PATH(data, 'one', '$.user')先判断父路径是否存在 - 多层嵌套建议拆成子查询或用
CASE WHEN分段 fallback,比如:SELECT CASE WHEN data->>'$.user' IS NOT NULL THEN data->>'$.user.name' ELSE 'anonymous' END AS name
- 对关键字段做
COALESCE(data->>'$.x.y.z', 'default'),但注意:如果z是NULL,COALESCE仍生效;如果y不存在,整个表达式就是NULL,COALESCE才接管
性能隐患:JSON 字段无法走索引,->> 不等于可优化
->> 表达式本身不阻止查询使用索引,但它包裹的列(如 json_col->>'$.status')**永远无法命中普通 B+Tree 索引**。即使你给这个表达式建了生成列 + 索引,也得手动维护。
线上慢查常源于在 WHERE 里直接写 meta->>'$.type' = 'order',导致全表扫描 JSON 字段。
- 高频查询的 JSON 子字段,务必冗余为普通列(如
status VARCHAR(20)),并在业务写入时同步更新 - 必须用 JSON 查询?MySQL 5.7+ 支持虚拟列 + 索引:
ALTER TABLE t ADD status_gen VARCHAR(20) GENERATED ALWAYS AS (meta->>'$.status') STORED; ALTER TABLE t ADD INDEX idx_status (status_gen);
-
JSON_CONTAINS和JSON_OVERLAPS在某些场景下可走函数索引(MySQL 8.0.13+),但路径必须字面量,不能是变量










