高频查询JSON字段必须用STORED虚拟列+普通B-Tree索引,因MySQL不支持直接对JSON列建索引;建表须用JSON类型以启用校验、路径查询与二进制解析优化;WHERE中应使用->>提取原生类型值并配合COALESCE设默认值,路径含特殊字符时用方括号语法;数组与存在性判断须用JSON_CONTAINS等专用函数,避免LIKE误匹配;虚拟列类型必须与JSON实际值类型严格一致,否则索引失效。

直接用 JSON 类型存,但不建索引就等于裸奔——高频查询字段必须走 STORED 虚拟列 + 普通 B-Tree 索引,否则每次 WHERE 都全表扫描解析 JSON。
建表时必须用 JSON 类型,别用 VARCHAR 或 TEXT
用 VARCHAR 存 JSON 字符串看似省事,实则丢掉全部能力:无格式校验、无法路径查询、不能建索引、解析全靠应用层。MySQL 会把 JSON 列转为内部二进制格式,读取时跳过文本解析,速度提升明显。
- 合法插入必须是标准 JSON:键和字符串值都用双引号,不能有尾随逗号,
'{"theme":"dark"}'✅,{"theme":'dark'}❌(单引号非法) - 空值处理:字段允许
NULL才能插NULL;否则用'{}'或'[]' - 想从字符串转 JSON,必须显式
CAST('{"a":1}' AS JSON),否则 MySQL 自动当普通字符串处理
查询必须分清 -> 和 ->>,WHERE 条件里几乎只用 ->>
-> 返回带引号的 JSON 字符串(如 "\"dark\""),->> 返回去引号后的原生类型(如 dark)。在 WHERE 中做等值比较时,用 -> 会导致隐式类型转换或引号匹配失败,极易出错。
- 安全写法:
WHERE config->>'$.theme' = 'dark' - 错误写法:
WHERE config->'$.theme' = '"dark"'(引号易漏、大小写敏感、空格容错差) - 路径含空格或特殊字符:用方括号语法,如
config->>'$.["screen size"]' - 路径不存在时返回
NULL,可用COALESCE(config->>'$.language', 'en')设默认值
高频查询字段必须建 STORED 虚拟列 + 索引,VIRTUAL 不行
MySQL 不允许直接对 JSON 列建索引,但支持基于表达式创建虚拟列再索引。关键点是:必须用 STORED,且提取操作必须是 ->> + 显式类型声明,否则索引无效。
- 正确示例:
ALTER TABLE user_config ADD theme VARCHAR(20) AS (config->>'$.theme') STORED;,再CREATE INDEX idx_theme ON user_config(theme); - 常见失效组合:
AS (config->'$.theme')(用了->)、VIRTUAL(8.0.13 前不可索引)、VARCHAR(255)(过长导致索引前缀截断,应按实际值长度设) - 验证是否真生效:用
EXPLAIN查type是否为ref或range,rows是否显著小于总行数,Extra不能有Using filesort
数组和存在性判断必须用专用函数,别手写 LIKE
查 JSON 数组是否包含某值、对象是否存在某个键,不能靠 INSTR 或 LIKE '%value%',会误匹配子字符串或嵌套结构。
- 判断数组含值:
JSON_CONTAINS(config, '"dark"', '$.themes')(第二个参数必须是 JSON 格式字符串,带双引号) - 判断键是否存在:
JSON_CONTAINS_PATH(config, 'one', '$.notification')('one'表示至少一个匹配) - 查嵌套对象是否非空:
config->'$.custom_shortcuts' IS NOT NULL,不是config->>'$.custom_shortcuts' != ''
最常被忽略的是虚拟列类型与实际 JSON 值类型的对齐——比如 JSON 里 "font_size": 14 是整数,却定义成 VARCHAR,索引就无法用于数值比较;反过来,字符串值定义成 INT 会截断。类型必须严丝合缝,否则索引形同虚设。


















