mysql 5.7+ 查 json 字段应使用 ->> 操作符(自动去引号并转类型),如 where info->>'$.role' = 'admin';路径需合法 jsonpath,含特殊字符时用双引号括起键名。

MySQL 5.7+ 怎么查 JSON 字段里的某个 key
直接用 -> 或 ->> 操作符,别先转成字符串再正则匹配——慢且不可靠。
-> 返回带引号的 JSON 字符串(比如 "admin"),->> 自动去引号并转类型(比如变成纯文本 admin),做 WHERE 条件时几乎总该用 ->>。
- 查用户角色:
SELECT * FROM users WHERE info->>'$.role' = 'admin'; - 查嵌套字段:
SELECT info->>'$.address.city' FROM users; - 注意路径必须是合法 JSONPath,
$开头,单引号包裹整个路径字符串 - 如果 key 名含点号或空格,得用双引号括起来:
info->>'$.["first.name"]'
PostgreSQL 的 jsonb 字段为什么用 @> 比 = 更靠谱
因为 = 要求两个 jsonb 完全一致(顺序、空格、键顺序都得一样),而实际写入时客户端序列化行为不统一,容易误判相等。
@> 是“包含”操作符,只关心结构和值是否覆盖,更符合业务语义。比如你想找所有启用了通知的用户,只要他们 JSON 里有 {"notify": true} 就行,不管其他字段有没有、顺序如何。
- 安全写法:
SELECT * FROM profiles WHERE settings @> '{"notify": true}'; - 避免写:
settings = '{"notify": true}'—— 看似一样,但可能因格式差异返回空结果 - 复合条件用
&&(重叠)或?(存在 key):settings ? 'theme' AND settings @> '{"active": true}'
JSON 字段建索引到底有没有用?怎么建才生效
有用,但必须用「函数索引」,而且查询写法要跟索引定义严格对齐,否则优化器直接忽略。
MySQL 用 GENERATED COLUMN + INDEX,PostgreSQL 直接在表达式上建索引。关键是:索引里的表达式,必须和 WHERE 中出现的表达式完全一致(包括是否用 -> 还是 ->>)。
- MySQL 示例:先加虚拟列
ALTER TABLE users ADD role VARCHAR(20) AS (info->>'$.role');,再建索引CREATE INDEX idx_role ON users(role); - PostgreSQL 示例:
CREATE INDEX idx_settings_notify ON profiles ((settings->>'notify'));,之后查询必须写WHERE settings->>'notify' = 'true' - 别对整个 JSON 字段建普通 B-tree 索引——没意义,它不理解内部结构
- jsonb 的 GIN 索引适合模糊查 key 或多层嵌套,但写法更复杂,日常单 key 查询用表达式索引更稳
从 JSON 字段取值时 NULL 和缺失 key 的区别处理
很多 bug 出在这儿:以为 info->>'$.phone' 返回 NULL 就代表字段不存在,其实它也可能是因为 phone 显式存了 null,或者路径压根写错了。
MySQL 用 JSON_CONTAINS_PATH 判断 key 是否存在;PostgreSQL 用 ? 操作符或 jsonb_path_exists。
- MySQL 判定 key 是否真存在:
JSON_CONTAINS_PATH(info, 'one', '$.phone')返回 1 才算有这个 key - PostgreSQL 判定:
info ? 'phone'(仅顶层)或jsonb_path_exists(info, '$.phone')(支持路径) - 写 WHERE 时别直接
WHERE info->>'$.phone' IS NOT NULL——它会把显式null和路径错误混为一谈 - 如果业务上“没填”和“填了 null”语义不同,必须拆开判断,不能偷懒
JSON 查询看着简单,但路径写错、索引不生效、NULL 处理模糊这三处,占了线上问题的八成。尤其是跨团队协作时,不同服务往同一个 JSON 字段写数据,格式稍有出入,查询就静默失效。










