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的話就不能使用索引,也就是說對於這種情況是不可用的。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM