概述
我們都知道where條件如果在欄位上帶了函數就不會去走索引,不好優化,無意間了解到mysql一個新特性--虛擬列,專門處理這塊問題的,下面一起來了解下吧~
Generated Column
在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默認的方式
語法
[ GENERATED ALWAYS ] AS ( ) [ VIRTUAL|STORED ]
[ UNIQUE [KEY] ] [ [PRIMARY] KEY ] [ NOT NULL ] [ COMMENT]
應用場景
假設有一個表,其中包含一個 date 類型的列 `SimpleDate` date
SimpleDate 是一個常用的查詢欄位,並需要對其執行日期函數,例如
SELECT ... WHERE dayofweek(SimpleDate) = 3 ...
此時的問題是 即使對 SimpleDate 建立索引,這個查詢語句也無法使用,因為日期函數阻止了索引。
為了提高查詢效率,通常要進行額外的操作,例如新建一個欄位 SimpleDate_dayofweek,存放 dayofweek(SimpleDate) 的計算結果,然後對這列創建索引,SimpleDate_dayofweek 的值需要程序寫入,例如使用觸發器,在 SimpleDate 有變動時更新這樣查詢就可以改為
SELECT ... WHERE SimpleDate_dayofweek = 3 ...
這麼做的好處是提高了查詢性能,可以使用 SimpleDate_dayofweek 列的索引了,但又帶來了其他麻煩,例如
- 降低了數據寫入性能
- 增加冗餘數據,占用了更多的存儲空間
- 增加代碼維護成本
虛擬列 Generated Columns 就是用來解決這個問題的,可以增加一個可被索引的列,但實際上並不存在於數據表中,下面用一個實驗來說明下:
實驗
需求:為了實現對json數據中部分數據的索引查詢,考慮用MySQL5.7中的虛擬列功能
1、創建表
create table user(uid int auto_increment,data json,primary key(uid));
2、準備數據
insert into user values (NULL,'{"name":"hwb","address":"guangzhou"}');
insert into user values (NULL,'{"name":"tqy","address":"shenzhen"}');
commit;
3、構建姓名的虛擬列
alter table user add user_name varchar(20) generated always as (data->'$.name');
4、構建索引
alter table user add index idx_name(user_name);
5、測試是否用到索引
explain select * from user where user_name='"hwb"' \\G;
可以看出用了索引了
6、插入新數據
此時的表的結構由於多出了user_name這一虛擬列,再插入別的數據要注意在表後指明插入列(不能給虛擬列插入數據)
insert into user(uid,data) values (NULL,'{"name":"test","address":"shantou"}');
做完發現這個實驗好像不是那麼好理解...應該對比一下加不加虛擬列有沒走索引,可能會更容易讓大家理解的...後面會分享更多devops和DBA方面的內容,感興趣的朋友可以關注一下~