資料庫優化SQL優化之SELECT優化 ——group by 優化
在資料庫查詢中,group by語句經常使用,而這個語句的使用是最耗效能的,按常理,
我們生活中要這樣做也很麻煩,有兩種情形:
1、有索引的情況
2、無索引的情況
對於第一種情況,如果在生活中要做這樣的事情,很惱火,我們正常的想法是,先把所有的
按高矮順序來排序,最後是一組的就直接挑出來了,但 怎樣實現這個排序呢?
根據上一篇檔案排序filesort的規則,我們可以這樣,先讓區域性有序,然後在慢慢擴散
來排列整個資料,方法是:選擇適當的大小的排序塊快取大小,每次取出塊大小資料,利用
快速排序功能對該塊排序,然後存入臨時檔案,然後利用歸併排序的思想,將各個塊之間進行
排序,最終達到排序完成。
對於上面的描述,雖然排序使用了非常快的排序演算法快排和歸併排序,但這個涉及的臨時
檔案的讀取操作,浪費大量的I/O,效能上是危害很大的,因此,掌握好在使用group by的語句的
使用,儘量使用到索引,免除了排序的操作,group by的速度就上來了,並且也不會消耗太多
記憶體大小,下面敘述一下group by使用索引的原理
一、 group by 使用索引原理
1、group by 使用排序來讀取資料,所以只能用btree索引,不能使用在hash索引的演算法中
因為hash索引是一種類似鍵值對的快速訪問方式,這個對於指定某個值查詢很好,但
沒有排序的方法,其使用的hash函式 + 碰撞衝突解決方案
2、當使用索引排序來查詢資料時,不會在explain中extra列看到有using filesort
3、在group by操作完成後,還會對group出來的結果進行排序,因此如果對排序的結果
沒有排序的需求,可以考慮在其後面加上order by null
二、group by 訪問索引的方法
group by 訪問資料有兩種方法:
1、邊掃描邊執行group操作,叫做鬆散索引掃描(Loose index scan)
2、先執行一個範圍(range)掃描,然後在執行group 操作,叫做
緊索引掃描(Tight index scan)
2.1、鬆散索引掃描(Loose index scan)
最高效的 處理group by的方法是,直接訪問相應的索引,所以不用排序就能根據
索引來讀取需要的資料,而對於如聚簇索引(cluster index),我們可以讀取前面的一部分
的欄位索引來獲取資料,而不用滿足所有的列,這就叫做鬆散索引掃描,我的定義可為:
字首索引掃描
使用鬆散索引掃描的條件:
1、查詢只能針對一個單表進行操作,這個可是個致命的缺點啊,但如果where
條件比較多,選出來的資料少的話,還是不用擔憂的
2、group by使用索引為:對聚簇索引使用字首索引
3、使用類似group by 的操作的函式有distinct函式,使用此函式時,要麼在一個
索引上使用,要麼在group by時,其group by的字句是索引掃描,否則會引
起全表掃描。
4、在使用group by語句中,如果使用聚合函式max(), min()等,如果列不在group
by的列中,或不在group by 列的聚簇索引的一部分,這將會用到排序操作
5、只能對整個列的值排序時使用到索引,而只有前面一部分索引不能用到排序,
如: 列 c1 char(20), index(c1(10))、這個只用了一半索引,將無法使用來對
整個資料排序
假設我們在表t1(c1, c2, c3, c4)有聚簇索引index(c1, c2, c3),能使用Loose index scan例子:
1、SELECT c1, c2 FROM t1 GROUP BY c1, c2;
2、SELECT DISTINCT c1, c2 FROM t1;
3、SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
4、SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
5、SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2;
6、SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
7、SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2;
原因解釋:
這些都使用了字首索引
2.2、使用緊索引掃描和鬆索引掃描類似,只是會先根據where條件來獲取所有的行,然後
根據group by的欄位來分組,這種的使用方法,一般是,where條件返回的行較少時
使用,比如,你的where字句中使用了主鍵或唯一鍵=const等,這樣的代價是,通過
where過濾出來的行很少,再分組操作時也很快的