MySQL Json类型支持通过虚拟列方式建立索引_mysql 为json列中的某字段创建虚拟列-程序员宅基地

技术标签: mysql  

  1. 背景

* 在MySQL 5.7.8中,MySQL支持由RFC 7159定义的本地JSON数据类型,它支持对JSON(JavaScript对象标记)文档中的数据进行有效访问.

* MySQL会对DML JSON数据自动验证。无效的DML JSON数据操作会产生错误.

  • 优化的存储格式。存储在JSON列中的JSON文档转换为一种内部格式,允许对Json元素进行快速读取访问.

  • MySQL Json类型支持通过虚拟列方式建立索引,从而增加查询性能提升.

  1. Json 索引

    • 创建Json索引表 json_key [ name 为虚拟列, virtual 表明不占用磁盘空间 ]

[ GENERATED ALWAYS 与 VIRTUAL可以不写 ]

    指定获取json中的name key

mysql> CREATE TABLE json_key(
-> uid BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT,
-> data JSON NOT NULL,
-> name VARCHAR(32) GENERATED ALWAYS AS (json_extract(data, ‘$.name‘)) VIRTUAL,
-> )ENGINE=INNODB CHARSET=utf8mb4;

  • 插入数据带 data中name key [ 插入数据时需要显示指定非虚拟列 ]

mysql> INSERT INTO json_key(uid, data) SELECT NULL, JSON_OBJECT(‘name‘, ‘tom‘, ‘sex‘, ‘male‘, ‘age‘, ‘26‘);
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0

  • 插入数据不带 data中name key

mysql> INSERT INTO json_key(uid, data) SELECT NULL, JSON_OBJECT(‘sex‘, ‘female‘, ‘age‘, ‘29‘);
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0

  • 查看json_key所有数据

mysql> select * from json_key;
±----±--------------------------------------------±------+
| uid | data | name |
±----±--------------------------------------------±------+
| 1 | {“age”: “26”, “sex”: “male”, “name”: “tom”} | “tom” |
| 2 | {“age”: “29”, “sex”: “female”} | NULL |
±----±--------------------------------------------±------+
2 rows in set (0.01 sec)

mysql原生并不支持json列中的属性索引,但是我们可以通过mysql的虚拟列间接的为json中的某些属性创建索引,原理就是为json中的属性创建虚拟列,然后通过给虚拟列建立索引,从而间接的给属性创建了索引。

在MySQL 5.7中,支持两种Generated Column,即Virtual Generated Column和Stored Generated Column,前者只将Generated Column保存在数据字典中(表的元数据),并不会将这一列数据持久化到磁盘上;后者会将Generated Column持久化到磁盘上,而不是每次读取的时候计算所得。很明显,后者存放了可以通过已有数据计算而得的数据,需要更多的磁盘空间,与Virtual Column相比并没有优势,因此,MySQL 5.7中,不指定Generated Column的类型,默认是Virtual Column。

如果需要Stored Generated Golumn的话,可能在Virtual Generated Column上建立索引更加合适,一般情况下,都使用Virtual Generated Column,这也是MySQL默认的方式

许你写的格式如下:

fieldname [ GENERATED ALWAYS ] AS ( ) [ VIRTUAL|STORED ] [ UNIQUE [KEY] ] [ [PRIMARY] KEY ] [ NOT NULL ] [ COMMENT ]
首先我们创建一张带有虚拟列的表新表:

CREATE TABLE players (
id INT UNSIGNED NOT NULL primary key auto_increment,
player JSON NOT NULL,
vname VARCHAR(50) GENERATED ALWAYS AS (player ->> ‘$.name’) NOT NULL – name的虚拟列
);
利用操作符-» 来引用JSON字段中的KEY。在本例中字段names_virtual为虚拟字段,我把它定义成不可以为空。在实际的工作中,需要结合具体的情况来定。因为JSON本身是一种弱结构的数据对象。也就是说的它的结构不是固定不变的。

然后我们查一下这个表的列有哪些:

SHOW COLUMNS FROM players;
结果如下,会发现vname的附加信息里面显示列类型为虚拟生成列:

在这里插入图片描述

然后,我们写一个存储过程,向表中插入八百万条记录,写之前先执行确认开启mysql存储过程:

show variables like ‘log_bin_trust_function_creators’; – 查看是否开启存储函数
set global log_bin_trust_function_creators=1; – 开启mysql存储函数
存储过程:

delimiter c r e a t e p r o c e d u r e i n s e r t p l a y e r ( i n m a x n u m i n t ( 10 ) ) b e g i n d e c l a r e i i n t d e f a u l t 0 ; d e c l a r e j s o n d a t a v a r c h a r ( 2000 ) d e f a u l t ′ 1 ′ ; s e t a u t o c o m m i t = 0 ; r e p e a t s e t i = i + 1 ; s e t j s o n d a t a = c o n c a t ( c o n c a t ( ′ " n a m e " : " y a o m i n g − ′ , i ) , ′ " , " a g e " : 34 , " g e n d e r " : " m a n " , " t y p e " : " b a s k e t B a l l " ′ ) ; i n s e r t i n t o p l a y e r s ( i d , p l a y e r ) v a l u e s ( n u l l , j s o n d a t a ) ; u n t i l i = m a x n u m e n d r e p e a t ; c o m m i t ; e n d create procedure insert_player(in max_num int(10)) begin declare i int default 0; declare json_data varchar(2000) default '1'; set autocommit= 0; repeat set i=i+1; set json_data = concat(concat('{"name":"yaoming-',i),'","age":34,"gender":"man","type":"basketBall"}'); insert into players (id,player) values(null,json_data); until i=max_num end repeat; commit; end createprocedureinsertplayer(inmaxnumint(10))begindeclareiintdefault0;declarejsondatavarchar(2000)default1;setautocommit=0;repeatseti=i+1;setjsondata=concat(concat("name":"yaoming,i),","age":34,"gender":"man","type":"basketBall");insertintoplayers(id,player)values(null,jsondata);untili=maxnumendrepeat;commit;end
调用一下存储过程,插入2000000条记录:

call insert_player(2000000);
插入完毕,总共耗时:

在这里插入图片描述

在添加索引之前我们先通过vname直接查询name为yaoming-990099的那条记录,总共耗时3.107s:

在这里插入图片描述

我们看一下这条语句的查询计划:

EXPLAIN SELECT * FROM players WHERE vname = “yaoming-990099”
结果如下:

在这里插入图片描述

然后我们为vname添加索引:

CREATE INDEX name_idx ON players(vname);

在这里插入图片描述
再次查询这条语句的执行计划:

在这里插入图片描述

速度已经快到飞起了!!!

我们在看一下查询计划详情:

在这里插入图片描述

发现已经走了索引查询!

但是需要注意的是,这种方法只能只能对json的某个单值属性或者给数组中的某一个特定位置上的元素有效,如果你想给对象数组中的所有元素的某个属性使用索引,那么最后你只能匹配数组中的所有对象的该属性或者使用like,但是使用like的话就不能使用索引,也就是说对于这种情况是不可用的

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wangjianwangzhefeng/article/details/109049906

智能推荐

【深度学习】归一化_深度学习 那些情况 要做 归一化-程序员宅基地

文章浏览阅读1.8w次,点赞8次,收藏11次。​ 以前在神经网络训练中,只是对输入层数据进行归一化处理,却没有在中间层进行归一化处理。要知道,虽然我们对输入数据进行了归一化处理,但是输入数据经过 $ \sigma(WX+b) $ 这样的矩阵乘法以及非线性运算之后,其数据分布很可能被改变,而随着深度网络的多层运算之后,数据分布的变化将越来越大。如果我们能在网络的中间也进行归一化处理,是否对网络的训练起到改进作用呢?答案是肯定的。​ 这种在神经网络中间层也进行归一化处理,使训练效果更好的方法,就是批归一化Batch Normalization(BN)。_深度学习 那些情况 要做 归一化

微信小程序支付接口实现(java后台)_小程序后台java支付接口-程序员宅基地

文章浏览阅读1.2w次,点赞12次,收藏101次。#(Notice:以下所有经验也是我根据网上的经验整理的,如有侵权可以联系我删除,QQ 654303408。 有问题讨论也可联系我,QQ同上。)#(Tips:我是第一次开发,一个刚毕业的java工程师,我觉得我并非天赋异禀,我能学会,相信聪敏的你,一定可以)#(PS:目前微信拥有无可撼动的人口基数,越来越多的项目开发是基于微信小程序,或者APP。但是支付方式无非两种,一种是支付宝,一种是微信支..._小程序后台java支付接口

python web server_用Python建立最简单的web服务器-程序员宅基地

文章浏览阅读27次。第一个python Web程序——简单的Web服务器。与其它Web后端语言不同,Python语言需要自己编写Web服务器。如果你使用一些现有的框架的话,可以省略这一步;如果你使用Python CGI编程的话,也可以省略这一步;用Python建立最简单的web服务器利用Python自带的包可以建立简单的web服务器。在DOS里cd到准备做服务器根目录的路径下,输入命令:python -m Web服务..._pyjwt webserver

【图像重建指标 Metrics】均方误差RMSE及平均绝对误差MAE的定义和区别_rmse与mae有换算公式吗-程序员宅基地

文章浏览阅读1.3w次,点赞3次,收藏23次。RMSE和MAE能很好的反应图像的重建结果与真实结果间的差异。_rmse与mae有换算公式吗

Kotlin Gradle Junit单元测试print输出控制台_gradle 打印日志 system. out.print-程序员宅基地

文章浏览阅读3.4k次。背景默认情况下,Gradle 单元测试,是无法使用 System.out.println 这样打印变量信息的,这会让我们debug变得非常麻烦。百度网上很多方案,,但都比较麻烦,也很容易踩坑,。换了个搜索姿势,google了下,原来方案如此简单。解决在你的模块下的build.gradle.kts添加如下的配置:tasks.withType<Test> { this.testLogging { this.showStandardStreams = true _gradle 打印日志 system. out.print

Android基本组件之服务Service_安卓如果设置组服务-程序员宅基地

文章浏览阅读167次。Service的开启与关闭1.继承Service类2.在AndroidManifest.xml中注册<service android:name=".MyService" android:enabled="true" android:exported="true"></service>直接创建Service的话,前两步会自动执行3.通过Contex.startSer..._安卓如果设置组服务

随便推点

sqlmap的使用--绕过--自带脚本tamper_sqlmap绕过脚本-程序员宅基地

文章浏览阅读2.2k次,点赞2次,收藏11次。sqlmap在默认的的情况下除了使用char()函数防止出现单引号,没有对注入的数据进行修改,还可以使用–tamper参数对数据做修改来绕过waf等设备。命令格式:sqlmap -u [url] --tamper [模块名]通过使用whereis sqlmap查看sqlmap安装路径,自带的脚本一般是在usr/share/sqlmap/tamper下,我的是1.6.3版本一共有66个自带脚本下边引一些常用的脚本:apostrophemask.py适用数据库:ALL作用_sqlmap绕过脚本

换行分隔符_分隔符 换行-程序员宅基地

文章浏览阅读1.7k次。windows:\r\nlinux:\rmac:\n_分隔符 换行

waves效果器_混音选择困难2,Waves均衡器全介绍与理论使用心得-程序员宅基地

文章浏览阅读4.2k次,点赞2次,收藏8次。喜欢「音乐杂谈」这个主题的朋友可以关注我的头条号,将会在不定期发表一些音乐理论以外的音乐话题的文章或者是音乐知识的干货 。(此文为混音师天职老师 发布于今日头条的原创文章,转载请告知并注明出处)通篇写作整理下来差不多花了7个小时,不管怎样,施舍点个赞吧。哈哈哈!继上一次「音乐杂谈41」混音选择困难第一期,给大家介绍了Waves全家桶的大部分压缩器之后,本篇,我们将来看看,Waves全家桶的大部分均..._waves功能详解

在Android中播放音频和视频_android 播放语言视频-程序员宅基地

文章浏览阅读2.8k次。Android媒体包提供了可管理各种媒体类型的类。这些类可提供用于执行音频和视频操作。除了基本操作之外,还可提供铃声管理、脸部识别以及音频路由控制。本文说明了音频和视频操作。本文简介媒体包提供了可管理各种媒体类型的类。这些类可提供用于执行音频和视频操作。除了基本操作之外,还可提供铃声管理、脸部识别以及音频路由控制。本文说明了音频和视频操作。范围:_android 播放语言视频

Sublime and Markdown-程序员宅基地

文章浏览阅读2.7k次。Sublime & Markdown文章目录Sublime & Markdown安装 Sublime设置 Sublime安装插件Package ControlMarkdownEditingMarkdown PreviewLiveReloadauto-saveOmniMarkupPreviewerEvernote插件&主题插入图片Ctrl+vHTML语法Markdown语法...

android uboot log,RK3288 Android 8.1系统uboot logo过渡到kernel logo会花一下-程序员宅基地

文章浏览阅读695次。在调试RK3288 Android 8.1系统遇到一个问题:开机启动uboot logo过渡到kernel log的过程中会花掉直到没有显示,再出现kernel logo。分析:打印串口log时发现,uboot阶段显示一切正常,进入kernel以后就开始花掉了然后变成没有显示了,感觉像是慢慢掉电了一样,再继续查看log发现如下打印:[ 0.363167] Registered fiq deb..._mtk 转屏后 logo uboot 转kernel 显示异常

推荐文章

热门文章

相关标签