group by的一些優化方案


從哪些方向去優化呢?

  • 方向1: 既然它默認會排序,我們不給它排是不是就行啦。
  • 方向2:既然臨時表是影響group by性能的X因素,我們是不是可以不用臨時表?

我們一起來想下,執行group by語句為什么需要臨時表呢?group by的語義邏輯,就是統計不同的值出現的個數。如果這個這些值一開始就是有序的,我們是不是直接往下掃描統計就好了,就不用臨時表來記錄並統計結果啦?

  • group by 后面的字段加索引
  • order by null 不用排序
  • 盡量只使用內存臨時表
  • 使用SQL_BIG_RESULT

5.1 group by 后面的字段加索引

如何保證group by后面的字段數值一開始就是有序的呢?當然就是加索引啦。

我們回到一下這個SQL

select city ,count(*) as num from staff where age= 19 group by city;
復制代碼

它的執行計划

如果我們給它加個聯合索引idx_age_city(age,city)

alter table staff add index idx_age_city(age,city);
復制代碼

再去看執行計划,發現既不用排序,也不需要臨時表啦。

加合適的索引是優化group by最簡單有效的優化方式。

5.2 order by null 不用排序

並不是所有場景都適合加索引的,如果碰上不適合創建索引的場景,我們如何優化呢?

如果你的需求並不需要對結果集進行排序,可以使用order by null

select city ,count(*) as num from staff group by city order by null
復制代碼

執行計划如下,已經沒有filesort

5.3 盡量只使用內存臨時表

如果group by需要統計的數據不多,我們可以盡量只使用內存臨時表;因為如果group by 的過程因為數據放不下,導致用到磁盤臨時表的話,是比較耗時的。因此可以適當調大tmp_table_size參數,來避免用到磁盤臨時表

5.4 使用SQL_BIG_RESULT優化

如果數據量實在太大怎么辦呢?總不能無限調大tmp_table_size吧?但也不能眼睜睜看着數據先放到內存臨時表,隨着數據插入發現到達上限,再轉成磁盤臨時表吧?這樣就有點不智能啦。

因此,如果預估數據量比較大,我們使用SQL_BIG_RESULT 這個提示直接用磁盤臨時表。MySQl優化器發現,磁盤臨時表是B+樹存儲,存儲效率不如數組來得高。因此會直接用數組來存

示例SQl如下:

select SQL_BIG_RESULT city ,count(*) as num from staff group by city;
復制代碼

執行計划的Extra字段可以看到,執行沒有再使用臨時表,而是只有排序

執行流程如下:

  1. 初始化 sort_buffer,放入city字段;
  2. 掃描表staff,依次取出city的值,存入 sort_buffer 中;
  3. 掃描完成后,對 sort_buffer的city字段做排序
  4. 排序完成后,就得到了一個有序數組。
  5. 根據有序數組,統計每個值出現的次數。

6. 一個生產慢SQL如何優化

最近遇到個生產慢SQL,跟group by相關的,給大家看下怎么優化哈。

表結構如下:

CREATE TABLE `staff` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `id_card` varchar(20) NOT NULL COMMENT '身份證號碼',
  `name` varchar(64) NOT NULL COMMENT '姓名',
  `status` varchar(64) NOT NULL COMMENT 'Y-已激活 I-初始化 D-已刪除 R-審核中',
  `age` int(4) NOT NULL COMMENT '年齡',
  `city` varchar(64) NOT NULL COMMENT '城市',
  `enterprise_no` varchar(64) NOT NULL COMMENT '企業號',
  `legal_cert_no` varchar(64) NOT NULL COMMENT '法人號碼',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='員工表';
復制代碼

查詢的SQL是這樣的:

select * from t1 where status = #{status} group by #{legal_cert_no}

作者:撿田螺的小男孩
鏈接:https://juejin.cn/post/7053966777088213005
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

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



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