MySQL5.7利用虛擬列優化
導 讀
知數堂只分享乾貨,各精品課程講授的都是職場實用技能
今天線上發生CPU使用率超過95%的報警, 登上RDS以後發現一堆的sending data狀態的SQL,大致有3個問題SQL,因為這3個SQL導致了其他原本很快的SQL也被“拖慢了”,以下是其中的一個SQL,拿出來記錄一下
建表DDL:
首先,看下執行計劃:從執行計劃裡可以看到,如下展示的部分沒有用到索引,並且在與表task log關聯時也沒有走索引,這裡有點特殊的情況就是t4跟t1關聯是3個欄位關聯。建立以下索引:再來看執行計劃:
從執行計劃看,問題就只剩下子查詢的部分,如果這個部分能用到索引,那麼這個SQL基本上就能達到要求了
先看下執行時間:
總共執行時間為90ms
再來分析下子查詢的部分:
這個部分是根據user_id,task_id,date分組,而date又是把created_at欄位格式化後取日期的部分,這個部分是沒有辦法直接用到索引的
查詢了下生產環境的RDS版本為5.7.18,可以用5.7的虛擬列完美解決這個問題呀!
先來看下MySQL官方文件關於虛擬列咋寫的:
虛擬列分為VIRTUAL和STORED兩種,兩者的區別是VIRTUAL只是在讀行的時候計算結果,但在物理上是不儲存的,並且InnoDB引擎支援在虛擬列上建二級索引;
而STORED則是當行資料進行插入或更新時計算並存儲的,是需要佔用物理空間的,並且也可以新增為索引列。
但虛擬列在實際使用過程中也需要注意如下:
1、虛擬列支援使用內建函式和運算子,但不能使用 CONNECTION_ID(), CURRENT_USER(), NOW()
2、子查詢、引數、變數、 儲存函式和自定義函式都無法使用虛擬列可以參照其他的虛擬列,但是參照的虛擬列必須定義在前面,假如參照的列為非虛擬列,那麼該列可以定義在虛擬列的前後
3、自增屬性無法使用在虛擬列並且自增列不能作為基礎列
4、MySQL5.7.10版本,如果表示式計算造成截斷或將錯誤資料傳入函式,CREATE TABLE語句會造成錯誤並且DDL操作會被拒絕
OK,大致瞭解了虛擬列,我們看下DDL語法
回到正題上來,首先,增加虛擬列:對虛擬列建立索引:再看下執行計劃:從執行計劃上看,子查詢的部分也已經用上了剛剛對虛擬列建立的索引,但是可以注意到有兩個warnings。可以看到的是新增的date跟原先DATE_FORMAT(created_at, '%Y-%m-%d')是重名的,這個地方也是本次優化一個需要注意的地方,雖然這裡報了warning,但是我們可以巧妙地解決無需修改線上程式碼就能達到優化的結果
看下執行結果:
可見,整個執行效果在21ms左右,效能提升4.3倍。
但是有點小小強迫症,讓開發儘快修改程式碼,SQL修改如下:
最後生產環境上線以後,由原先的378ms提升到36ms,提升了10.5倍,效果還是很明顯的。

原文釋出時間為:2018-12-5
本文作者:徐晨亮
本文來自雲棲社群合作伙伴“ ofollow,noindex">老葉茶館 ”,瞭解相關資訊可以關注“iMySQL_WX”微信公眾號