Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >MySQL · 最佳实践 · 如何索引JSON字段

MySQL · 最佳实践 · 如何索引JSON字段

作者头像
保持热爱奔赴山海
发布于 2019-09-17 06:05:11
发布于 2019-09-17 06:05:11
3.4K00
代码可运行
举报
文章被收录于专栏:数据库相关数据库相关
运行总次数:0
代码可运行

原文地址: http://mysql.taobao.org/monthly/2017/12/09/

MySQL · 最佳实践 · 如何索引JSON字段

概述

MySQL从5.7.8起开始支持JSON字段,这极大的丰富了MySQL的数据类型。也方便了广大开发人员。但MySQL并没有提供对JSON对象中的字段进行索引的功能,至少没有直接对其字段进行索引的方法。本文将介绍利用MySQL 5.7中的虚拟字段的功能来对JSON对象中的字段进行索引。

示例数据

我们将基于下面的JSON对象进行演示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    "id": 1,  
    "name": "Sally",  
    "games_played":{    
       "Battlefield": {
          "weapon": "sniper rifle",
          "rank": "Sergeant V",
          "level": 20
        },                                                                                                                          
       "Crazy Tennis": {
          "won": 4,
          "lost": 1
        },  
       "Puzzler": {
          "time": 7
        }     } }

表的基本结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE TABLE `players` (  
    `id` INT UNSIGNED NOT NULL,    `player_and_games` JSON NOT NULL,    PRIMARY KEY (`id`)
);

如果只是基于上面的表的结构我们是无法对JSON字段中的Key进行索引的。接下来我们演示如何借助虚拟字段对其进行索引

增加虚拟字段

虚拟列语法如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<type> [ GENERATED ALWAYS ] AS ( <expression> ) [ VIRTUAL|STORED ][ UNIQUE [KEY] ] [ [PRIMARY] KEY ] [ NOT NULL ] [ COMMENT <text> ]

在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默认的方式

加完虚拟列的建表语句如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE TABLE `players` (  
   `id` INT UNSIGNED NOT NULL,   `player_and_games` JSON NOT NULL,   `names_virtual` VARCHAR(20) GENERATED ALWAYS AS (`player_and_games` ->> '$.name') NOT NULL, 
   PRIMARY KEY (`id`)
);

Note: 利用操作符-» 来引用JSON字段中的KEY。在本例中字段names_virtual为虚拟字段,我把它定义成不可以为空。在实际的工作中,一定要集合具体的情况来定。因为JSON本身是一种弱结构的数据对象。也就是说的它的结构不是固定不变的。

我们插入数据

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
INSERT INTO `players` (`id`, `player_and_games`) VALUES (1, '{  
    "id": 1,  
    "name": "Sally",
    "games_played":{    
       "Battlefield": {
          "weapon": "sniper rifle",
          "rank": "Sergeant V",
          "level": 20
        },                                                                                                                          
       "Crazy Tennis": {
          "won": 4,
          "lost": 1
        },  
       "Puzzler": {
          "time": 7
        }
      }
   }');...

查看表里的数据

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT * FROM `players`;

+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+
| id | player_and_games                                                                                                                                                                                           | names_virtual |
+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+
|  1 | {"id": 1, "name": "Sally", "games_played": {"Puzzler": {"time": 7}, "Battlefield": {"rank": "Sergeant V", "level": 20, "weapon": "sniper rifle"}, "Crazy Tennis": {"won": 4, "lost": 1}}}                  | Sally         |
|  2 | {"id": 2, "name": "Thom", "games_played": {"Puzzler": {"time": 25}, "Battlefield": {"rank": "Major General VIII", "level": 127, "weapon": "carbine"}, "Crazy Tennis": {"won": 10, "lost": 30}}}            | Thom          |
|  3 | {"id": 3, "name": "Ali", "games_played": {"Puzzler": {"time": 12}, "Battlefield": {"rank": "First Sergeant II", "level": 37, "weapon": "machine gun"}, "Crazy Tennis": {"won": 30, "lost": 21}}}           | Ali           |
|  4 | {"id": 4, "name": "Alfred", "games_played": {"Puzzler": {"time": 10}, "Battlefield": {"rank": "Chief Warrant Officer Five III", "level": 73, "weapon": "pistol"}, "Crazy Tennis": {"won": 47, "lost": 2}}} | Alfred        |
|  5 | {"id": 5, "name": "Phil", "games_played": {"Puzzler": {"time": 7}, "Battlefield": {"rank": "Lt. Colonel III", "level": 98, "weapon": "assault rifle"}, "Crazy Tennis": {"won": 130, "lost": 75}}}          | Phil          |
|  6 | {"id": 6, "name": "Henry", "games_played": {"Puzzler": {"time": 17}, "Battlefield": {"rank": "Captain II", "level": 87, "weapon": "assault rifle"}, "Crazy Tennis": {"won": 68, "lost": 149}}}             | Henry         |
+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+

查看表Players的字段

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SHOW COLUMNS FROM `players`;

+------------------+------------------+------+-----+---------+-------------------+
| Field            | Type             | Null | Key | Default | Extra             |
+------------------+------------------+------+-----+---------+-------------------+
| id               | int(10) unsigned | NO   | PRI | NULL    |                   |
| player_and_games | json             | NO   |     | NULL    |                   |
| names_virtual    | varchar(20)      | NO   |     | NULL    | VIRTUAL GENERATED |
+------------------+------------------+------+-----+---------+-------------------+

我们看到虚拟字段names_virtual的类型是VIRTUAL GENERATED。MySQL只是在数据字典里保存该字段元数据,并没有真正的存储该字段的值。这样表的大小并没有增加。我们可以利用索引把这个字段上的值进行物理存储。

在虚拟字段上加索引

再添加索引之前,让我们先看下面查询的执行计划

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
EXPLAIN SELECT * FROM `players` WHERE `names_virtual` = "Sally"\G  
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE        table: players
   partitions: NULL
         type: ALLpossible_keys: NULL  
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
     filtered: 16.67
        Extra: Using where

添加索引

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE INDEX `names_idx` ON `players`(`names_virtual`);

再执行上面的查询语句,我们将得到不一样的执行计划

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
EXPLAIN SELECT * FROM `players` WHERE `names_virtual` = "Sally"\G  
*************************** 1. row ***************************           id: 1
  select_type: SIMPLE        table: players
   partitions: NULL         type: refpossible_keys: names_idx  
          key: names_idx      key_len: 22          ref: const         rows: 1     filtered: 100.00        Extra: NULL

如我们所见,最新的执行计划走了新建的索引。

小结

本文介绍了如何在MySQL 5.7中保存JSON文档。为了高效的检索JSON中内容,我们可以利用5.7的虚拟字段来对JSON的不同的KEY来建索引。极大的提高检索的速度。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/03/03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
LeetCode MySQL 550. 游戏玩法分析 IV
每一行是一个玩家的记录,他在某一天使用某个设备注销之前登录并玩了很多游戏(可能是 0)。
Michael阿明
2021/02/19
4630
不看后悔 —— 视图详细介绍
在MySQL中,视图可能是我们最常用的数据库对象之一了。那么你知道视图和表的区别吗?你知道创建及使用视图要注意哪些点吗?可能很多人对视图只是一知半解,想详细了解视图的同学看过来哟,本篇文章会详细介绍视图的概念、创建及使用方法。
MySQL技术
2019/12/25
5900
大数据系列思考题----[持续更新]
个人理解: hdfs启动流程 hdfs是Hadoop Distribute File System 的简称,即分布式文件系统,用于存储海量数据. hdfs的启动分为三步:1.启动Namenode;2.启动Datanode;3.启动Secondary Namenode; 详细说说: Secondary NameNode的工作流程:(为了方便Secondary NameNode以SN替代,NameNode)首先SN通知NN切换成edits文件; NN中的edits和fsimage通过http的方式传输到SN,并在SN中合并成新的fsimage.ckpt,之后传输回NN,并将旧的fsimage替换; NN中的edits生成新的edits文件并替换旧的edits
Maynor
2021/04/09
7040
千呼万唤始出来,MySQL 8.0索引三剑客之函数索引
独孤九剑,重剑无锋,大巧不工,通晓剑意,无所施而不可。三剑客之首,函数索引。 函数索引这个概念并不新颖,Oracle早在十年前的Oracle10g中就支持了函数索引,函数索引在Oracle数据库中使用相当广泛和成熟,而MySQL却一直没有开发相关的索引功能。不过好消息是,MySQL 终于在8.0版本引入了这一特性。真的是,千呼万唤始出来,不过好歹还是来了。
吹水老王
2022/05/17
1.8K0
MySQL 5.7新特性| Json Column和Generated Column(下)
JSON 字段类型在当前的版本中自身没有索引,那么在生产中是非常可怕的,JSON 字段的增、删、改、查效率可想而知,基本没法用,也许是基于此,MySQL5.7 中提供了 Generated 字段类型,网上有叫生成列或是计算列的。这里先来了解一下什么是 Generated Column。
wubx
2019/02/27
8500
最佳实践 · 如何高效索引MySQL JSON字段
从MySQL 5.7.8版本开始,MySQL引入了对JSON字段的支持,这为处理半结构化数据提供了极大的灵活性。然而,MySQL原生并不支持直接对JSON对象中的字段进行索引。本文将介绍如何利用MySQL 5.7中的虚拟字段功能,对JSON字段中的数据进行高效索引,以提高查询性能。
不惑
2024/09/10
5690
最佳实践 · 如何高效索引MySQL JSON字段
PokéLLMon 源码解析(五)
ApacheCN_飞龙
2024/03/08
1560
LeetCode MySQL 512. 游戏玩法分析 II
这个表显示的是某些游戏玩家的游戏活动情况 每一行是在某天使用某个设备登出之前登录并玩多个游戏(可能为0)的玩家的记录 请编写一个 SQL 查询,描述每一个玩家首次登陆的设备名称
Michael阿明
2021/02/19
6220
LeetCode MySQL 534. 游戏玩法分析 III
编写一个 SQL 查询,同时报告每组玩家和日期,以及玩家到目前为止玩了多少游戏。 也就是说,在此日期之前玩家所玩的游戏总数。详细情况请查看示例。
Michael阿明
2021/02/19
3760
运维实践|MySQL命令之mysqlshow
我是一名开发运维工程师,之前就有看到过有人说开发与运维就是挖坑和填坑的关系」。开发和运维之间确实存在密切的关系,但是就上述观点有失公平,过于片面。这样子说,会给所有开发者一个先入为主的不好印象,误导项目团队成员认为开发只是在制造问题,而运维只是在解决问题。实际上,开发工程师和运维工程师应该是协作的关系,只不过开发工程师交付在前,运维工程师维护在后。
六月暴雪飞梨花
2023/12/22
6424
运维实践|MySQL命令之mysqlshow
技术应用|MySQL命令之mysqlshow
我是一名开发运维工程师,之前就有看到过有人说开发与运维就是挖坑和填坑的关系」。开发和运维之间确实存在密切的关系,但是就上述观点有失公平,过于片面。这样子说,会给所有开发者一个先入为主的不好印象,误导项目团队成员认为开发只是在制造问题,而运维只是在解决问题。实际上,开发工程师和运维工程师应该是协作的关系,只不过开发工程师交付在前,运维工程师维护在后。
艾特
2023/12/28
2010
技术应用|MySQL命令之mysqlshow
LeetCode MySQL 1097. 游戏玩法分析 V
我们还将某个日期 X 的第 1 天留存时间定义为安装日期为 X 的玩家的数量,他们在 X 之后的一天重新登录,除以安装日期为 X 的玩家的数量,四舍五入到小数点后两位。
Michael阿明
2021/02/19
4350
探索MySQL 5.7 虚拟列 (virtual columns)
在MySQL 5.7中,支持两种Generated Column,即Virtual Generated Column和Stored Generated Column,前者只将Generated Column保存在数据字典中(表的元数据),并不会将这一列数据持久化到磁盘上;后者会将Generated Column持久化到磁盘上,而不是每次读取的时候计算所得。很明显,后者存放了可以通过已有数据计算而得的数据,需要更多的磁盘空间,与Virtual Column相比并没有优势,因此,MySQL 5.7中,不指定Generated Column的类型,默认是Virtual Column。
兔云小新LM
2020/05/19
2.2K0
MySQL 支持JSON字段的基本操作、相关函数及索引使用如何索引JSON字段
Mysql5.7版本以后新增的功能,Mysql提供了一个原生的Json类型,Json值将不再以字符串的形式存储,而是采用一种允许快速读取文本元素(document elements)的内部二进制(internal binary)格式,并提供了不少内置函数,通过计算列,甚至还可以直接索引json中的数据。
chenchenchen
2022/03/09
29.9K0
MySQL 之 JSON 支持(二)—— JSON 索引
从 MySQL 8.0.17 开始,InnoDB 支持多值索引。多值索引是在存储数组值的列上定义的辅助索引。“一般”索引对于每个数据记录有一个索引记录(1:1)。多值索引中单个数据记录可以具有多个索引记录(N:1)。多值索引用于对 JSON 数组进行索引。例如,在下面的 JSON 文档中,对邮政编码数组定义的多值索引为每个邮政编码创建一个索引记录,每个索引记录引用相同的数据记录。
用户1148526
2024/06/07
5700
Vc数据库编程基础MySql数据库的表查询功能
  不管是任何数据库.都会有查询功能.而且是很重要的功能.上一讲知识简单的讲解了表的查询所有.
IBinary
2019/05/25
9.7K0
MySQL 5.7新特性| Json Column 和 Generated Column(上)
MySQL5.7 新增两种字段类型:Json 和 Generated,Generated 型的产生和 Json 的关系密不可分,如果没有Generated 类型,Json 类型在强大,生产中可能也无法使用,因为 Json 不支持索引,但是如果要查询 Json 里的数据,没有索引就是全表扫描,在执行效率上肯定是不能用于生产环境的,但是有了 Generated 类型就不同了,Generated 类型简单地说是一个虚拟字段,值是不可更新的,值来源其他字段或者字段间计算或是转化而来的,这种类型是可以创建索引,利用 Generated 的特性,就可以间接的给 Json 类型中的 key 创建索引,解决 Json 不能创建索引的问题。简而言之, Generated 类型的产生,为 Json 类型在索引方面的问题提供了支持。JSON 的值包含单个值、数组、元组、标注的 Json 格式等几种格式。
wubx
2019/02/27
2.1K0
MySQL存储过程的创建及调用
    1.创建存储过程     2.调用存储过程     3.存储过程体     4.语句块标签
别先生
2021/12/09
3K0
LeetCode 数据库专题
写一段SQL查询来展示每位用户的 唯一标识码(unique ID );如果某位员工没有唯一标识码,使用 null 填充即可。你可以以 任意 顺序返回结果表。查询结果的格式如下例所示:
wywwzjj
2023/05/09
1.5K0
LeetCode 数据库专题
使用 MySQL 5.7 虚拟列提高查询效率
大约两年前,我发表了一个在MySQL5.7版本上关于虚拟列的文章。从那时开始,它成为MySQL5.7发行版当中,我最喜欢的一个功能点。原因很简单:在虚拟列的帮助下,我们可以创建间接索引(fine-grained indexes),可以显著提高查询性能。我要告诉你一些技巧,可以潜在地解决那些使用了GROUP BY 和 ORDER BY而慢的报表查询。
wubx
2019/02/27
4.1K0
推荐阅读
相关推荐
LeetCode MySQL 550. 游戏玩法分析 IV
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验