mysql 8.0 json性能提升源于底层二进制存储、部分更新、json_table下推及虚拟列索引等实质性升级,非配置开关;用错语法(如直接表达式建索引、滥用json_contains)反而比varchar更慢。

MySQL 8.0 的 JSON 字段性能提升不是靠“配置开关”来的,而是底层存储、解析和索引机制的实质性升级。你改不改配置,只要用对了语法和结构,性能差异就客观存在。
JSON 存储格式从文本变成二进制
MySQL 5.7 虽然引入了 JSON 类型,但内部仍偏向文本解析;MySQL 8.0 完全采用优化的二进制格式(类似紧凑的 AST),包含字段偏移、类型标记、键名字典等元数据。
- 查询时不用逐字节解析字符串,
JSON_EXTRACT(data, '$.user.name')直接跳转到目标位置,时间复杂度接近 O(1) - 插入/更新时支持部分修改:改一个
skuid不会重写整个 JSON 文档,InnoDB 可以只更新 LOB 中的对应片段(Partial Update of LOB Column特性) - 旧版 VARCHAR 存 JSON 每次都要
SUBSTRING_INDEX或正则硬匹配,8.0 下这类操作已无必要
JSON_TABLE 让嵌套查询真正可下推
在处理 {"orders": [{"items": [{"skuid": 1001}]}]} 这类结构时,JSON_EXTRACT 是纯计算函数,无法走索引、不能下推条件、每次调用都全量解析整棵树。
-
JSON_TABLE把解析动作提前到执行计划生成阶段,输出的是标准虚拟表,WHERE、JOIN、ORDER BY全部能下推到引擎层 - 必须显式写
ON EMPTY NULL ON ERROR NULL,否则某条记录字段类型不匹配(比如"1001"字符串 vs INT),整行直接丢弃,不是填 NULL - 嵌套超过 3 层(如 orders → items → options → price)时,
NESTED PATH层级链变长,解析开销回升,建议提前扁平化或拆表
虚拟列 + STORED 索引让 JSON 路径可命中 B+ 树
你不能对 data->>'$.status' 直接建索引——MySQL 8.0 会报错 ERROR 3105,因为 B+ 树索引不接受运行时表达式。
- 必须用
GENERATED ALWAYS AS (data->>'$.status') STORED创建虚拟列,再在该列上建普通索引 - 用
->>(去引号标量)而非->(带引号 JSON),否则类型是json,无法和字符串常量高效比较 - 查询时 WHERE 条件必须写成
WHERE status = 'shipped',写成WHERE data->>'$.status' = 'shipped'就完全不走索引 - 路径不存在时
->>返回NULL,所以WHERE status IS NULL可走索引,但= ''不行
最易被忽略的一点:JSON 性能优势只在“用对方式”时生效。把 JSON 当字符串拼接、在 WHERE 里狂套 JSON_CONTAINS、不建虚拟列却指望 ->> 走索引——这些都会让 MySQL 8.0 的 JSON 反而比 VARCHAR 更慢。











