Mysql字符集對關聯查詢的影響

最近有個需要對生產環境數據進行修復,量比較大,單個sql關聯千萬數據的表更新幾萬到幾十萬不等,sql如下:

UPDATE month_201601_count t1

JOIN app_car_sum_daily_event_copy t2 ON (

t1.carid = t2.car_id

AND t1.date = DAYOFMONTH(t2.date)

)

SET t1.accelerateTimes = t2.accelerate_times,

 t1.decelerateTimes = t2.decelerate_times,

 t1.sharpTurnTimes = t2.sharp_turn_times

WHERE

t2.date >= '2016-01-01'

AND t2.date < '2016-02-01';


直接在生產環境跑,也沒怎麼在意,畢竟sql之前開發提過來經過優化執行過的,應該沒什麼問題,幾個小時過去回頭來看的時候居然一個sql都沒跑完,show innodb狀態看到該事務才掃描出幾萬條數據,按這效率估計一個星期

才能跑完一條sql,趕緊停了看看情況,首先看了一下執行計劃:

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

沒有按照事先考慮好的t2表驅動t1表,如果用t1表驅動t2在date字段有函數用不了索引,而且t1表還是用date字段做了分區的表,主鍵爲(carid,date),按理想中的t2驅動t1表主鍵索引應該都會用上,還能定位t1的分區表,現在這樣的方式效率肯定大打折扣,再仔細看看執行計劃發現ref列出現了func,意思就是在對t2表值進行關聯時了用了function,這個有點坑,立馬用explain extended加show warnings看下具體情況,因爲update語句不支持extended選項寫了個關聯查詢的語句:

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

這就坑了,居然在關聯字段carid上面做了字符集轉換,去查看錶結構發現t1 表爲utf8、t2 表時utf8mb4,utf8mb4是utf8的超集,在編碼上有所不同,mysql內部會發生轉換,那麼把t2表的字符集同樣修改爲utf8再看執行計劃:

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

變成了預期所想的t2作爲驅動表,ref列已經出現鏈接字段的情況,依然看到有func,不過這不影響,因爲函數應用在t2表關聯時的條件值上面,在生產環境中改了t2表字符集之後單個sql執行時間在一分鐘左右,成功解決問題


發生這種函數轉化有可能是全表掃描了,雖然說執行計劃顯示用了索引其實有可能並沒有,可以開trace查看,開trace很簡單

set optimizer_trace="enabled=on",並把optimizer_trace_max_mem_size調大點,不然計劃內容多了裝不完,下面把t1和t2兩個表字符集對換做的驗證:


可以看到驅動變爲了t2,t1也使用了primary索引,轉換變成了t2表的字符集,這可以得出個結論字符集轉換都是由低向高轉化的,再看看trace跟蹤信息

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

可以看出t1表是使用了全表掃描的,並不像顯示的那樣使用了索引,最開始沒有調換字符集的時候t2表是使用了索引,但是發生了函數轉化依然會降低執行效率


在生產環境中一定需要注意字符集統一,當然也可以在只需要emoji表情的表設置utf8mb4,前提得控制好關聯查詢,統一字符集可以避免時間久了搞忘,從而產生這種關聯查詢效率低的問題


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章