MySQL 5.7 的 JSON 函数仅支持运行时解析,无法建立有效索引;8.0 引入函数索引、JSON_TABLE() 等功能,显著提升 JSON 查询性能与操作能力。

MySQL 5.7 的 JSON 函数只能“解析”,不能“索引”
5.7 支持 JSON_EXTRACT()、->、->>、JSON_CONTAINS() 等基础函数,但所有操作都在查询时重新解析整段 JSON 文本。你写 WHERE data->>'$.status' = 'active',优化器根本不会考虑走索引——它压根不支持对这类表达式建索引。
常见错误现象:
- 建了
JSON_EXTRACT(data, '$.id')的 VIRTUAL 生成列,却报错ERROR 3105 (HY000): Expression of generated column cannot be used in index - 用了 STORED 生成列并建了索引,但查询仍写
data->>'$.id'而不是生成列名,导致索引完全失效 -
JSON_UNQUOTE(JSON_EXTRACT(data, '$.email'))和data->>'$.email'在语义上等价,但 5.7 不识别这种等价性,索引不会被复用
MySQL 8.0 开始支持函数索引,JSON 查询真正可加速
8.0 允许直接在表达式上建索引,语法就是 CREATE INDEX idx_status ON users ((data->>'$.status')) ——注意双层括号,外层是语法必需,内层才是表达式本身。这条语句会真实构建 B+ 树索引,内容是每个 data 字段中 $.status 解析后的字符串值。
关键约束和实操要点:
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
-
CAST(... AS CHAR)或CAST(... AS DATETIME)常需显式指定,因为 InnoDB 不允许直接索引 JSON 类型 - 表达式必须是确定性的:
JSON_EXTRACT()可以,但NOW()、RAND()、用户变量不行 - 索引长度受
innodb_page_size限制,路径太长(如'$.metadata.tags[*].name')可能被截断,导致部分匹配失效 - 升级后若还留着 5.7 的 STORED 生成列,建议删掉——它们已无存在必要,反而占空间、拖慢 DML
8.0 新增的 JSON 函数让复杂操作不再绕路
5.7 完全没有 JSON_TABLE(),遇到 {"items": [{"id":1},{"id":2}]} 这种结构,只能靠应用层解析或写恶心的自连接模拟;而 8.0 可直接展开为行集:
SELECT * FROM JSON_TABLE(
'[{"id":1,"name":"a"},{"id":2,"name":"b"}]',
'$[*]' COLUMNS (id INT PATH '$.id', name VARCHAR(10) PATH '$.name')
) AS jt;其他新增函数也直击痛点:
-
JSON_MERGE_PATCH()实现原子级差异更新,避免整 JSON 重写 -
JSON_ARRAYAGG()和JSON_OBJECTAGG()支持 GROUP BY 聚合,5.7 只能靠应用拼接 -
JSON_CONTAINS_PATH()检查路径是否存在,比JSON_EXTRACT() IS NOT NULL更高效且语义清晰
容易被忽略的兼容性细节
函数行为看似一致,但底层校验逻辑不同:
- 8.0 默认启用更严格的 UTF8MB4 完整性校验 + Unicode 代理对检查,单次
->>解析开销比 5.7 高,但配合函数索引后总体更快 -
->和->>在 5.7.13+ 才支持,旧版只能用JSON_EXTRACT()+JSON_UNQUOTE() - 排序规则差异:8.0 默认
utf8mb4_0900_ai_ci,与 5.7 常用的utf8mb4_general_ci在大小写/重音处理上不一致,影响ORDER BY data->>'$.name'结果 - 认证插件变更间接影响 JSON 使用:老版 JDBC 驱动连不上 8.0,默认报
Authentication plugin 'caching_sha2_password' cannot be loaded,得先改插件或升级驱动

















