mysql group by執行原理


mysql中group by實現方式有三種,松散索引,緊湊索引,臨時文件(文件排序)。

在網上看了相關的介紹,大部分介紹都比較晦澀難懂,這里說下我的理解。

在學習SQL優化時,我們都知道可以對group by進行優化的方式就是對group by引用的字段建立索引。當group by引用多個字段時,我們建立的相應的索引也應包含多個字段。

對group by操作優化的原理就是讓mysql利用索引,而避免進行建立臨時表,進而進行文件排序(group by的第三種實現方式)。

對於group by引用的多個字段,需滿足於所建立索引的最左前綴索引,否則進行group by操作時,無法利用索引。在利用索引時,group by可根據索引,即可對數據分組,此時完全不用去

訪問表的數據值(索引健對應的數據)。這種實現方式就是利用松散索引。

當group by引用的字段無法構成所建索引的最左前綴索引時,也就是說group by不能利用索引時。如何where語句(如果有的話)彌補了這種差距,比如:group by

引用的字段為(c2,c3),而索引為(c1,c2,c3)。此時如果where語句限定了c1=a(某一個值),那么此時mysql的執行過程為先根據where語句進行一次選擇,

對選出來的結果集,可以利用索引。這種方式,從整體上來說,group by並沒有利用索引,但是從過程來說,在選出的結果中利用了索引,這種方式就是緊湊索引。

這種方式,mysql的執行計划為using where,use index。而松散索引的執行計划為using index for group by。

如果mysql如論如何都不能利用索引時,此時mysql將讀取所有的數據建立臨時表,對文件進行排序,完成分組操作。

 

關於group的作用:

滿足於我們針對某些字段進行分組,然后在組內對多行數據進行處理(計算行數,計算max,min等等)這樣的需求。group by返回的數據是有序的。

如果我們對數據進行分組后,要輸出(select)其所有(多)行的數據,此時是無法實現的。根據版本的不同,可能會輸出第一行數據,可能會保錯。

 

 

 

 

轉:https://blog.csdn.net/qq403580298/article/details/90756352

寫在前面的話:用了好久group by,今天早上一覺醒來,突然感覺group by好陌生,總有個筋別不過來,為什么不能夠select * from Table group by id,為什么一定不能是*,而是某一個列或者某個列的聚合函數,group by 多個字段可以怎么去很好的理解呢?不過最后還是轉過來了,簡單寫寫吧,大牛們直接略過吧。

=========正文開始===========

  先來看下表1,表名為test:

 

表1

  執行如下SQL語句:

1
2
SELECT  name  FROM  test
GROUP  BY  name

  你應該很容易知道運行的結果,沒錯,就是下表2:

 

表2

  可是為了能夠更好的理解“group by”多個列“和”聚合函數“的應用,我建議在思考的過程中,由表1到表2的過程中,增加一個虛構的中間表:虛擬表3。下面說說如何來思考上面SQL語句執行情況:

1.FROM test:該句執行后,應該結果和表1一樣,就是原來的表。

2.FROM test Group BY name:該句執行后,我們想象生成了虛擬表3,如下所圖所示,生成過程是這樣的:group by name,那么找name那一列,具有相同name值的行,合並成一行,如對於name值為aa的,那么<1 aa 2>與<2 aa 3>兩行合並成1行,所有的id值和number值寫到一個單元格里面。

 

3.接下來就要針對虛擬表3執行Select語句了:

(1)如果執行select *的話,那么返回的結果應該是虛擬表3,可是id和number中有的單元格里面的內容是多個值的,而關系數據庫就是基於關系的,單元格中是不允許有多個值的,所以你看,執行select * 語句就報錯了。

(2)我們再看name列,每個單元格只有一個數據,所以我們select name的話,就沒有問題了。為什么name列每個單元格只有一個值呢,因為我們就是用name列來group by的。

(3)那么對於id和number里面的單元格有多個數據的情況怎么辦呢?答案就是用聚合函數,聚合函數就用來輸入多個數據,輸出一個數據的。如cout(id),sum(number),而每個聚合函數的輸入就是每一個多數據的單元格。

(4)例如我們執行select name,sum(number) from test group by name,那么sum就對虛擬表3的number列的每個單元格進行sum操作,例如對name為aa的那一行的number列執行sum操作,即2+3,返回5,最后執行結果如下:

 (5)group by 多個字段該怎么理解呢:如group by name,number,我們可以把name和number 看成一個整體字段,以他們整體來進行分組的。如下圖

(6)接下來就可以配合select和聚合函數進行操作了。如執行select name,sum(id) from test group by name,number,結果如下圖:

至此,我已經對我自己對如此簡單的問題有如此天馬行空的想法所折服,洗洗睡覺。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM