mysql中生成列與JSON類型的索引


MySQL中支持生成列,生成列的值是根據列定義中包含的表達式計算的。

一個簡單的例子來認識生成列!

CREATE TABLE triangle(
sidea DOUBLE,
sideb DOUBLE,
sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb))
);

INSERT INTO triangle(sidea, sideb)  VALUES(3,4),(6,8),(5,12);

mysql> select * from triangle;  #插入數值的時候並沒有插入c的值,但是查詢的時候,還是有了c值
+-------+-------+-------+
| sidea | sideb | sidec |
+-------+-------+-------+
|     3 |     4 |     5 |
|     6 |     8 |    10 |
|     5 |    12 |    13 |
+-------+-------+-------+
3 rows in set (0.00 sec)

mysql>

生成列中的值,是根據生成列的定義計算出來的

生成列的定義如下:

col_name data_type [GENERATED ALWAYS] AS (expression)
  [VIRTUAL | STORED] [NOT NULL | NULL]
  [UNIQUE [KEY]] [[PRIMARY] KEY]
  [COMMENT 'string']
#AS表達式表示生成列並用於計算生成列的表達式。As之前的GENERATED ALWAYS可以讓生成列的性質更明確(應該沒什么作用,反正是可以省略的)!
#VIRTUAL | STORED 關鍵字表示列值的存儲方式
  • VIRTUAL: 不存儲列值,但在讀取值之前立即計算此列的數值,虛擬列不占存儲空間,innodb支持虛擬列上的二級索引。為默認的存儲方式。
  •   STORED:插入或更新時,將計算存儲列的值,並且占用存儲空間。
 生成列的表達式必須遵循以下的規則,否則會報錯:
  1. 允許使用字符串,運算符和確定性內置函數。對於給定的相同的數據庫,不同連接的用戶調用會產生相同的結果,則這個函數時確定的。now()函數就不是確定性函數。
  2. 不允許使用子查詢,參數,變量,存儲函數(stored functions)和用戶自定義的函數。
  3. 生成的列定義可以引用其他生成的列,但只能引用表定義中較早出現的列。生成的列定義可以引用表中的任何基本(非生成)列,無論其定義是早期還是稍后發生
  4. auto_increment屬性不能再生成列的定義中使用。
  5. 一個AUTO_INCREMENT列不能用作在生成的列定義的基柱(An AUTO_INCREMENT column cannot be used as a base column in a generated column definition.)
  6. 從MySQL 5.7.10開始,如果表達式求值導致截斷或向函數提供不正確的輸入,則 CREATE TABLE語句將以錯誤終止並拒絕DDL操作

 生成列的作用(可能不太准確):

  • 虛擬生成的列可用作簡化和統一查詢的方法。可以將復雜條件定義為生成列,並從表上的多個查詢引用,以確保他們全部使用完全相同的條件。
  • 存儲生成的列可以用作物化緩存,用於復雜的條件,這些條件在運行中計算成本很高。
  • 生成列可以模擬功能索引,利用生成列定義功能表達式對其進行索引。例如對JSON數據類型。對於存儲的生成列,這種方法缺點是存儲兩次,一次是生成列的值,另一次是索引。
  • 如果生成的列已編制索引,則優化程序將識別與列定義匹配的查詢表達式,並在查詢執行期間根據需要使用列中的索引,即使查詢未按名稱直接引用該列也是如此。

如下一個含有json類型字段的表:

CREATE TABLE json_test (
    id INT auto_increment PRIMARY KEY,
    userinfo json
);

#插入數據

INSERT INTO json_test(userinfo) VALUES('{"name":"libai","address":"china","email":"libai@163.com"}');
INSERT INTO json_test(userinfo) VALUES('{"name":"obama","address":"miguo","email":"libai@gmail.com"}');
INSERT INTO json_test(userinfo) VALUES('{"name":"putin","address":"russia","email":"putin@gmail.com"}');

#

給表中添加生成列

alter table json_test add column user_name varchar(40) generated always  as (userinfo->"$.name") virtual;

#查看表中的數據
mysql> select * from json_test;
+----+--------------------------------------------------------------------+-----------+
| id | userinfo                                                           | user_name |
+----+--------------------------------------------------------------------+-----------+
|  1 | {"name": "libai", "email": "libai@163.com", "address": "china"}    | "libai"   |
|  2 | {"name": "obama", "email": "libai@gmail.com", "address": "miguo"}  | "obama"   |
|  3 | {"name": "putin", "email": "putin@gmail.com", "address": "russia"} | "putin"   |
+----+--------------------------------------------------------------------+-----------+
3 rows in set (0.00 sec)

#在表中插入數據user_name列的數值會自動計算,這時候,我們就可以對user_name列添加索引!

 


免責聲明!

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



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