滿足GROUP BY子句的最一般的方法是掃描整個表并創建一個新的臨時表,表中每個組的所有行應為連續的,然后使用該臨時表來找到組并應用累積函數(如果有)。在某些情況中,MySQL能夠做得更好,即通過索引訪問而不用創建臨時表。
為GROUP BY使用索引的最重要的前提條件是所有GROUP BY列引用同一索引的屬性,并且索引按順序保存其關鍵字。是否用索引訪問來代替臨時表的使用還取決于在查詢中使用了哪部分索引、為該部分指定的條件,以及選擇的累積函數。
由于GROUP BY 實際上也同樣會進行排序操作,而且與ORDER BY 相比,GROUP BY 主要只是多了排序之后的分組操作。當然,如果在分組的時候還使用了其他的一些聚合函數,那么還需要一些聚合函數的計算。所以,在GROUP BY 的實現過程中,與 ORDER BY 一樣也可以利用到索引。在MySQL 中,GROUP BY 的實現同樣有多種(三種)方式,其中有兩種方式會利用現有的索引信息來完成 GROUP BY,另外一種為完全無法使用索引的場景下使用。下面我們分別針對這三種實現方式做一個分析。
1、使用松散索引掃描(Loose index scan)實現 GROUP BY
對“松散索引掃描”的定義,本人看了很多網上的介紹,都不甚明白。在此邏列如下:
定義1:松散索引掃描,實際上就是當 MySQL 完全利用索引掃描來實現 GROUP BY 的時候,并不需要掃描所有滿足條件的索引鍵即可完成操作得出結果。
定義2:優化Group By最有效的辦法是當可以直接使用索引來完全獲取需要group的字段。使用這個訪問方法時,MySQL使用對關鍵字排序的索引的類型(比如BTREE索引)。這使得索引中用于group的字段不必完全涵蓋WHERE條件中索引對應的key。由于只包含索引中關鍵字的一部分,因此稱為松散的索引掃描。
意思是索引中用于group的字段,沒必要包含多列索引的全部字段。例如:有一個索引idx(c1,c2,c3),那么group by c1、group by c1,c2這樣c1或c1、c2都只是索引idx的一部分。要注意的是,索引中用于group的字段必須符合索引的“最左前綴”原則。group by c1,c3是不會使用松散的索引掃描的
例如:
explain
SELECT group_id,gmt_create
FROM group_message
WHERE user_id>1
GROUP BY group_id,gmt_create;
本人理解“定義2”的例子說明
有一個索引idx(c1,c2,c3)
SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
索引中用于group的字段為c1,c2
不必完全涵蓋WHERE條件中索引對應的key(where條件中索引,即為c1;c1對應的key,即為idx)
索引中用于group的字段(c1,c2)只包含索引中關鍵字(c1,c2,c3)的一部分,因此稱為松散的索引掃描。
要利用到松散索引掃描實現GROUP BY,需要至少滿足以下幾個條件:
新聞熱點
疑難解答