MySQL html
隨着業務量的增加,運營同事反饋有個報表頁面愈來愈慢,從對應的報表語句中逐個子查詢篩查,找出以下最慢的語句:mysql
能夠看到,其中有個子集全表掃了300多萬行數據。抽出來單獨explain,定位到問題語句:sql
SELECT t1.statDate, t1.tips .net
FROM passport_4366_test t1 htm
WHERE t1.statDate>='2016-05-01' blog
AND t1.statDate<='2016-05-05' 索引
GROUP BY t1.statDate, t1.tips; ip
檢查一下表結構發現,在表的statDate上明明創建了索引,照理說type應該是range纔對,怎麼會是all呢?get
去掉group by語句試試:
仍然是全表掃描。去掉一個字段再試試:
要掃描的數據量變成1/5,type也變成range了。那麼究竟是什麼緣由致使MySQL查詢執行器放棄使用索引直接進行全表掃描呢?去問問谷歌,搜索到以下可能有幫助的文章:
回顧一下,這個表字段是date類型,難道是由於這個表同一天產生太多數據下降了索引區分度導致查詢執行器放棄治療?那麼,把這個字段改爲datetime類型會不會好點?好,咱們來動手試試看。
create table passport_4366_test like passport_4366;
insert into passport_4366_test select * from passport_4366 where statDate>='2016-04-01' AND statDate<='2016-05-06';
alter table passport_4366_test add index dt_idx(updateTime);
alter table passport_4366_test drop index statDate;
而後explain看看:
真是頑固不化的MySQL,只好force index了:
終於乖乖聽話了。想起來還有一個解決思路,那就是創建聯合索引:
alter table passport_4366_test add index statDate_tips_idx(statDate, tips);
再來看看explain的結果:
效果很不錯,rows列比force index的結果還要好(多是由於Index Condition Pushdown Optimization)。拉大時間範圍,直接執行語句對比一下執行時間:
結果是聯合索引完勝。
最後,總結一下:
1. 創建索引時候儘可能選擇區分度大的列;
2. 適當條件下能夠考慮創建聯合索引,譬如本例中聯合索引的優點明顯;
3. 寫SQL的時候要多點explain,主要看type和rows,通常來講,執行效率const > eq_ref > ref > range > all,rows值越少越好。
參考文章:
http://blog.csdn.net/mchdba/article/details/9190771
https://www.percona.com/blog/2014/01/03/multiple-column-index-vs-multiple-indexes-with-mysql-56/
http://dev.mysql.com/doc/refman/5.6/en/index-condition-pushdown-optimization.html