zoukankan      html  css  js  c++  java
  • mysql 5.7 新特性之 json 类型 创建索引

    参考:https://blog.csdn.net/bugs4j/article/details/79932538

    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 <type> [ GENERATED ALWAYS ] AS ( <expression> ) [ VIRTUAL|STORED ] [ UNIQUE [KEY] ] [ [PRIMARY] KEY ] [ NOT NULL ] [ COMMENT <text> ]
     

    首先我们创建一张带有虚拟列的表新表:

    1.  
      CREATE TABLE players (
    2.  
      id INT UNSIGNED NOT NULL primary key auto_increment,
    3.  
      player JSON NOT NULL,
    4.  
      vname VARCHAR(50) GENERATED ALWAYS AS (`player` ->> '$.name') NOT NULL -- name的虚拟列
    5.  
      );

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

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

    SHOW COLUMNS FROM `players`;
     

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

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

    1.  
      show variables like 'log_bin_trust_function_creators'; -- 查看是否开启存储函数
    2.  
      set global log_bin_trust_function_creators=1; -- 开启mysql存储函数

    存储过程:

    1.  
      delimiter $$
    2.  
      create procedure insert_player(in max_num int(10))
    3.  
      begin
    4.  
      declare i int default 0;
    5.  
      declare json_data varchar(2000) default '1';
    6.  
      set autocommit= 0;
    7.  
      repeat
    8.  
      set i=i+1;
    9.  
      set json_data = concat(concat('{"name":"yaoming-',i),'","age":34,"gender":"man","type":"basketBall"}');
    10.  
      insert into players (id,player) values(null,json_data);
    11.  
      until i=max_num end repeat;
    12.  
      commit;
    13.  
      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的话就不能使用索引,也就是说对于这种情况是不可用的。

     
  • 相关阅读:
    那些好的句子
    ❤️博客使用说明-飞沙
    求n以内,除5的倍数的和
    C# 枚举
    2021年bilibili程序员节日
    MT管理器使用技巧
    腾讯找人工客服
    校报白皮书
    C语言教程(下)
    svn版本控制
  • 原文地址:https://www.cnblogs.com/kuangke/p/14702254.html
Copyright © 2011-2022 走看看