濮阳杆衣贸易有限公司

主頁 > 知識庫 > MySQL Group by的優(yōu)化詳解

MySQL Group by的優(yōu)化詳解

熱門標(biāo)簽:百應(yīng)電話機器人優(yōu)勢 外呼系統(tǒng)打電話上限是多少 電話外呼系統(tǒng)改號 地圖標(biāo)注費用是多少 怎樣在地圖標(biāo)注銷售區(qū)域 曲靖移動外呼系統(tǒng)公司 啥是企業(yè)400電話辦理 武漢網(wǎng)絡(luò)外呼系統(tǒng)服務(wù)商 南昌三維地圖標(biāo)注

一個標(biāo)準(zhǔn)的 Group by 語句包含排序、分組、聚合函數(shù),比如 select a,count(*) from t group by a ;  這個語句默認使用 a 進行排序。如果 a 列沒有索引,那么就會創(chuàng)建臨時表來統(tǒng)計 a和 count(*),然后再通過 sort_buffer 按 a 進行排序。

標(biāo)準(zhǔn)的執(zhí)行流程

結(jié)構(gòu):

create table t1(id int primary key, a int, b int, index(a));
delimiter ;;
create procedure idata()
begin
 declare i int;

 set i=1;
 while(i=1000)do
 insert into t1 values(i, i, i);
 set i=i+1;
 end while;
end;;
delimiter ;
call idata();

函數(shù)就是向 t1 中插入1000條語句,從(1,1,1) 到(1000,1000,1000)。

執(zhí)行   select id%10 as m, count(*) as c from t1 group by m;

解析:

Using index,表示這個語句使用了覆蓋索引,選擇了索引 a,不需要回表;
Using temporary,表示使用了臨時表;
Using filesort,表示需要排序。

過程:

1、創(chuàng)建內(nèi)存臨時表,表里有兩個字段 m 和 c,主鍵是 m;
2、掃描表 t1 的索引 a,依次取出葉子節(jié)點上的 id 值,計算 id%10 的結(jié)果,記為 x;
  1)如果臨時表中沒有主鍵為 x 的行,就插入一個記錄 (x,1);
  2)如果表中有主鍵為 x 的行,就將 x 這一行的 c 值加 1;

第2 步如果發(fā)現(xiàn)內(nèi)存臨時表存儲的總字段長度到達參數(shù) tmp_table_size 設(shè)置的大小,那么就會將內(nèi)存臨時表升級為磁盤臨時表,然后重新開始遍歷計算。
3、遍歷完成后,再根據(jù)字段 m 做排序,得到結(jié)果集返回給客戶端。

最后的排序就是下圖虛線框中的操作,如果 sort_buffer 設(shè)置的大小不夠大,那么就會使用臨時表來輔助排序。

優(yōu)化

未優(yōu)化(也就是分組列沒有索引)的 group by 的總過程可以概括為:因為數(shù)據(jù)是無序的,所以需要創(chuàng)建臨時表,然后一個一個判斷屬于哪個分組,最后再根據(jù)分組列進行排序。所以,優(yōu)化可以有兩個思路:

去掉排序

在明確返回的數(shù)據(jù)不需要排序的情況下,可以禁止排序,也就是將上面的語句改成 select a,count(*) from t group by a order by null。

順序排列

如果記錄都按照排序字段排序,那么數(shù)據(jù)就變成了下面的結(jié)構(gòu):

這樣在實際獲取要返回的字段或計算聚合函數(shù)時,只需要按順序依次訪問,等到列值變成下一個就知道當(dāng)前組訪問結(jié)束,將之前統(tǒng)計的數(shù)據(jù)直接返回。這樣就避免了創(chuàng)建臨時表,同時排序也不需要使用 sort_buffer 進行額外排序。這樣就極大地提高了執(zhí)行的效率。

實現(xiàn)

1、如果分組字段適合創(chuàng)建索引就直接為分組字段創(chuàng)建索引。

MySQL 5.7 版本支持了 generated column 機制,用來實現(xiàn)列數(shù)據(jù)的關(guān)聯(lián)更新。你可以用下面的方法創(chuàng)建一個列 z,然后在 z 列上創(chuàng)建一個索引(如果是 MySQL 5.6 及之前的版本,你也可以創(chuàng)建普通列和索引,來解決這個問題)

alter table t1 add column z int generated always as(id % 100), add index(z);

然后解析:

這時沒有用到臨時表和額外排序,所以性能提升。

2、如果分組字段不適合(使用率很低),那么可以使用 SQL_BIG_RESULT 來嘗試優(yōu)化。

在 group by 語句中加入 SQL_BIG_RESULT 這個提示(hint),就可以告訴優(yōu)化器:這個語句涉及的數(shù)據(jù)量很大,請直接用磁盤臨時表。MySQL 的優(yōu)化器一看,磁盤臨時表是 B+ 樹存儲,存儲效率不如數(shù)組來得高。所以,既然使用SQL_BIG_RESULT來說明數(shù)據(jù)量很大,那從磁盤空間考慮,還是直接用數(shù)組來存吧。所以在使用 SQL_BIG_RESULT 后優(yōu)化器會使用數(shù)組結(jié)構(gòu)的磁盤臨時表。

但是如果在未達到磁盤臨時表的使用條件是不會使用磁盤臨時表的,也就是在 sort_buffer 空間能夠存儲要返回和排序的總字段長度時,就使用數(shù)組結(jié)構(gòu)的 sort_buffer ,如果總字段超過 sort_buffer 大小,那么就再加上數(shù)組結(jié)構(gòu)的磁盤臨時表來幫助排序。

那么在 sort_buffer 空間足夠的情況下, sort_buffer 內(nèi)部就會對數(shù)據(jù)進行排序,這樣也就起到了索引的作用,

還是以上面的例子來看,使用 SQL_BIG_RESULT

alter table t1 add column z int generated always as(id % 100), add index(z);

具體過程如下:

1、初始化 sort_buffer,確定放入一個整型字段,記為 m;
2、掃描表 t1 的索引 a,依次取出里面的 id 值, 將 id%10 的值存入 sort_buffer 中;
3、掃描完成后,對 sort_buffer 的字段 m 做排序(如果 sort_buffer 內(nèi)存不夠用,就會利用磁盤臨時文件輔助排序);
4、排序完成后,就得到了一個有序數(shù)組。

解析:

可以看到此時就沒有使用臨時表了,而是直接使用 sort_buffer 進行排序,這樣就省去了使用臨時表帶來的性能消耗。

總結(jié)

1、如果對 group by 語句的結(jié)果沒有排序要求,要在語句后面加 order by null;那么一般情況就不需要使用臨時表了(上面兩個優(yōu)化都是在要求排序的前提下提出的優(yōu)化方式)
2、盡量讓 group by 過程用上表的索引,確認方法是 explain 結(jié)果里沒有 Using temporary 和 Using filesort;
3、如果 group by 需要統(tǒng)計的數(shù)據(jù)量不大,盡量只使用內(nèi)存臨時表;也可以通過適當(dāng)調(diào)大 tmp_table_size 參數(shù),來避免用到磁盤臨時表;
4、如果數(shù)據(jù)量實在太大,使用 SQL_BIG_RESULT 這個提示,來告訴優(yōu)化器直接使用排序算法得到 group by 的結(jié)果。

以上就是詳解MySQL Group by 優(yōu)化的詳細內(nèi)容,更多關(guān)于MySQL Group by 優(yōu)化的資料請關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:
  • MySQL group by語句如何優(yōu)化
  • MySQL優(yōu)化GROUP BY(松散索引掃描與緊湊索引掃描)
  • MySQL優(yōu)化GROUP BY方案

標(biāo)簽:滄州 錦州 隨州 黑河 吉林 荊州 甘南 資陽

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《MySQL Group by的優(yōu)化詳解》,本文關(guān)鍵詞  MySQL,Group,的,優(yōu)化,詳解,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《MySQL Group by的優(yōu)化詳解》相關(guān)的同類信息!
  • 本頁收集關(guān)于MySQL Group by的優(yōu)化詳解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    卫辉市| 彭水| 阿瓦提县| 隆昌县| 福泉市| 通城县| 宁津县| 新昌县| 象山县| 南投市| 上高县| 凤翔县| 湄潭县| 巴林右旗| 炎陵县| 保德县| 三台县| 同仁县| 新营市| 苗栗县| 运城市| 嘉祥县| 奇台县| 大同市| 涿鹿县| 阳泉市| 周至县| 钟山县| 河南省| 兴义市| 华蓥市| 剑阁县| 福建省| 伊金霍洛旗| 新河县| 青神县| 文化| 广宗县| 龙井市| 南乐县| 临澧县|