1. 程式人生 > >資料庫優化SQL優化之SELECT優化 ——group by 優化

資料庫優化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過濾出來的行很少,再分組操作時也很快的