mysql 8.0升级后json查询变慢主因是优化器无法为运行时json函数建索引,须用stored虚拟列提取路径值并显式建索引,且查询必须改写为查该列,否则仍全表扫描。

MySQL 升级后 JSON 解析变慢,不是偶然现象,而是优化器行为、校验逻辑和索引机制三重变更叠加的结果。8.0 对 JSON 的解析路径更严格、更完整,代价就是 CPU 和内存开销上升——尤其在没建对索引或写错查询条件时,性能会断崖式下跌。
JSON_CONTAINS 或 ->> 查询全表扫描(type: ALL)
这是最常见也最容易被误判的问题。MySQL 的 B+ 树索引无法作用于运行时函数调用,JSON_CONTAINS(meta, '"admin"', '$.roles') 或 data->>'$.status' 这类表达式在 WHERE 中出现,优化器根本看不到“结构”,只能全表解析每条 JSON。
- 错误示例:
CREATE INDEX idx ON t (data->>'$.status');→ 直接报错ERROR 3105 - 正确路径:必须先建
STORED虚拟列,再在该列上建普通索引 - 虚拟列定义必须用
->>(返回标量),不能用->(返回带引号字符串) - 类型要显式且紧凑:比如状态字段用
VARCHAR(20),别用TEXT或VARCHAR(255) - 查询时必须改写 WHERE 条件:✅
WHERE status = 'shipped';❌WHERE data->>'$.status' = 'shipped'
升级后 JSON 查询响应翻倍,但 EXPLAIN 显示 type: ref
这说明索引确实走了,但解析开销仍在。8.0 默认启用更严格的 UTF8MB4 校验和更完整的 JSON 语法验证,哪怕字段已建索引,每次匹配仍需校验编码合法性、路径是否存在、值是否为预期类型。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 虚拟列是
STORED才能规避重复解析:它把提取结果物理存下来,后续只比对索引值,不碰原始 JSON -
VIRTUAL列虽不占磁盘空间,但在某些执行计划(如 8.0.13 前的子查询优化路径)中可能退化为实时计算 - 路径不存在时
->>返回NULL,所以WHERE status IS NULL可走索引,但= ''不行 - 隐式类型转换会悄悄让索引失效:虚拟列是
INT,但 WHERE 里传'123'字符串,就会触发全表扫
ORDER BY JSON 字段或 JSON_CONTAINS 后排序明显卡顿
这不是 JSON 本身的问题,而是 MySQL 8.0 排序策略变更放大了 JSON 解析的副作用。优化器默认启用 hash_join 和 derived_merge,同时改用更激进的 filesort 策略——一旦排序字段没覆盖索引,就会强制内存排序;若 sort_buffer_size 不足或 JSON 字段太长,立刻落盘,IO 成瓶颈。
- 检查是否触发 filesort:
EXPLAIN看Extra列是否含Using filesort - 临时缓解:SQL 开头加
/*+ USE_INDEX(@sel_1 tbl_name (idx_status)) */强制走有序索引 - 长期解法:对排序字段补复合索引,例如
WHERE status = 'active' ORDER BY created_at,建INDEX(status, created_at) - 避免在 ORDER BY 中直接用
data->>'$.field':先提取到虚拟列,再对该列排序
真正容易被忽略的是:虚拟列 + 索引只是第一步,业务 SQL 必须同步改写。很多团队建完索引就以为万事大吉,结果老查询照旧跑得慢——因为优化器不会自动把 data->>'$.x' 映射过去,它只认你明确定义的列名。










