MySQL 8.0如何优化JSON字段的查询效率_通过虚拟列建立索引加速

梦杰姑娘_8841

梦杰姑娘_8841

2026-05-19

794人浏览

原创

必须用stored虚拟列提取json字段并显式声明类型后建索引,否则data->>'$.status'等查询无法走索引;因b+树索引不支持运行时函数,优化器无法识别表达式结构,导致全表扫描。

mysql 8.0如何优化json字段的查询效率_通过虚拟列建立索引加速

不能直接对 JSON 字段建索引,必须用虚拟列(STORED 更稳妥)提取路径值并显式声明类型,再在该列上建普通索引;否则所有 WHERE data->>'$.xxx' 查询都走全表扫描。

为什么 data->>'$.status' 查询不走索引

MySQL 的 B+ 树索引无法作用于运行时函数调用。每次执行 data->>'$.status' 都要解析整条 JSON、提取字段、去引号、比较——优化器看不到“结构”,只能全表扫。EXPLAIN 显示 type: ALL 就是这个原因。

  • JSON_EXTRACT()、JSON_CONTAINS()、JSON_OVERLAPS() 全部同理,不落地就无索引可言
  • 即使字段只有 1KB,10 万行也意味着 100GB+ 的 JSON 解析开销(含 CPU 和内存)
  • 错误示例:CREATE INDEX idx ON t (data->>'$.status'); 会报错 ERROR 3105

怎么安全添加虚拟列并建索引

关键不是加列,而是表达式、类型、存储方式三者匹配。错一个,索引就白建。

  • 必须用 ->>(不是 ->):前者返回标量值(如 active),后者返回带引号的 JSON 字符串(如 "active")
  • 类型必须显式且合理:字符串用 VARCHAR(64),数字用 INT UNSIGNED,时间用 DATETIME;别用 TEXT 或过大的 VARCHAR(255)
  • 优先选 STORED:物理存储值,索引行为稳定;VIRTUAL 在某些优化器路径下可能失效(尤其 MySQL 8.0.13 前)
  • 字段名不能和已有列或保留字冲突,比如别叫 order、group

正确示例:

Wjs Reframing Video
Wjs Reframing Video

用于在保持宽高比倒置的情况下,将视频从横向转换为纵向或反之(例如 16:9 ↔ 9:16,4:3 ↔ 3:4 等)

下载
ALTER TABLE orders ADD COLUMN status VARCHAR(20) GENERATED ALWAYS AS (data->>'$.status') STORED, ADD INDEX idx_status (status);

查询时必须改写 WHERE 条件

建完虚拟列后,老 SQL 不改,索引等于没建。优化器不会自动把 data->>'$.status' 映射到新列。

  • ✅ 走索引:SELECT * FROM orders WHERE status = 'shipped';
  • ❌ 不走索引(哪怕逻辑等价):SELECT * FROM orders WHERE data->>'$.status' = 'shipped';
  • ⚠️ 类型隐式转换风险:虚拟列是 INT,但传入字符串 '123',会导致索引失效;应统一用 123
  • ⚠️ 路径不存在时 ->> 返回 NULL,所以 WHERE status IS NULL 可走索引,但 = '' 不行

嵌套深、数组、多条件时怎么处理

虚拟列只适合扁平、稳定、高频查询的字段。一碰动态结构,就容易掉坑里。

  • $.items[0].id 这类带数组下标的路径不可靠:首项不稳定,生成列值可能随机为 NULL
  • 查多个字段(如 status 和 user_id):建两个虚拟列,再建复合索引 CREATE INDEX idx_st_uid ON orders (status, user_id)
  • JSON 里存时间戳(如 $.created_at):虚拟列必须用 DATETIME 类型,才能支持 BETWEEN 或 >=
  • 结构频繁变更(今天 $.status,下周改成 $.state):虚拟列维护成本高,不如应用层拆成普通字段

最常被忽略的一点:虚拟列本身不解决写入性能问题。每次 INSERT 或 UPDATE 都要重新计算表达式,路径越深、JSON 越大,写延迟越明显——读写比低于 5:1 时,得重新评估方案。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

mysql js json

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

2173

6

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.21

1319

5

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

775

5

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.19

2952

5

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.25

4948

4

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.08

1119

3

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

5211

4

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

2023.08.14

4582

7

mysql事务隔离级别
mysql事务隔离级别

mysql规范中定义了四种事务隔离级别,不同的隔离级别对事务的处理有所不同。本专题为大家提供mysql事务隔离级别相关的文章内容,大家可以免费体验。

2023.08.16

6054

11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 183人学习