group by 优化临时表

本文详细解释了MySQL在进行GROUPBY操作时利用索引优化的方法,并提供了三种实现方式及优化思路,包括利用索引扫描、创建临时表排序等,以及如何通过添加特定子句避免文件排序操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GROUP BY 优化之临时表

MySQL 在进行 GROUP BY 操作时要想利用索引,必须满足 GROUP BY 的字段同时存放于同一个索引中,且该索引是一个有序索引(如 Hash 索引就不能满足要求)。不仅如此,是否能够利用索引来实现 GROUP BY 还与使用的聚合函数有关系。

前面两种 GROUP BY 的实现方式都是在有可以利用的索引时使用的,当 MySQL Query Optimizer无法找到可以利用的合适索引时,就不得不先读取需要的数据,然后通过临时表来完成 GROUP BY 操作,如示例代码8-27所示:

代码8-27

  
  1. sky@localhost : example 09:02:40> EXPLAIN  
  2.     -> SELECT max(gmt_create)   
  3.     -> FROM group_message   
  4.     -> WHERE group_id > 1 and group_id < 10  
  5.     ->  GROUP BY user_id\G 

*************************** 1. row ***************************

  
  1.               id:   1  
  2.    select_type: SIMPLE  
  3.           table:    group_message  
  4.            type:    range  
  5. possible_keys:  idx_group_message_gid_uid,idx_gid_uid_gc  
  6.             key:    idx_gid_uid_gc  
  7.        key_len: 4  
  8.             ref:    NULL 
  9.            rows:    32  
  10. Extra:  Using where; Using index; Using temporary; Using filesort 

这次的执行计划非常明显地告诉了我们 MySQL 通过索引找到了所需的数据,然后创建了临时表,又进行了排序操作,才得到所需的 GROUP BY 结果。整个执行过程大概如图8-9所示:

 
(点击查看大图)图8-9

当 MySQL Query Optimizer 发现仅通过索引扫描并不能直接得到 GROUP BY 的结果时,它就不得不选择使用临时表,然后通过再排序的方式来实现 GROUP BY了。

本示例是这样的情况。group_id 并不是一个常量条件,而是一个范围,而且 GROUP BY 字段为 user_id。所以 MySQL 无法根据索引的顺序来帮助 GROUP BY 的实现,只能先通过索引范围扫描得到需要的数据,将数据存入临时表,然后再进行排序和分组操作来完成 GROUP BY。

对于上面三种 MySQL 处理 GROUP BY 的方式,可以针对性地得出如下两种优化思路:

(1)尽可能让 MySQL利用索引来完成 GROUP BY 操作,当然最好是松散索引扫描的方式。在系统允许的情况下,可以通过调整索引或调整 Query 这两种方式来达到目的;

(2)当无法使用索引完成 GROUP BY时,由于要使用到临时表且需要 filesort,所以必须要有足够的 sort_buffer_size供 MySQL排序时使用,而且尽量不要进行大结果集的 GROUP BY 操作,因为如果超出系统设置的临时表大小就会出现将临时表数据复制(copy)到磁盘上面再进行操作的情况,这时的排序分组操作性能将成数量级的下降。

至于如何利用好这两种思路,还须要大家在实际应用场景中不断地尝试并测试效果,才能最终得到较佳方案。此外,在优化 GROUP BY时还有一个小技巧可以让我们在有些无法利用到索引的情况下避免 filesort 操作,即在整个语句最后添加一个以 null 排序(ORDER BY null)的子句,大家可以尝试一下看会有什么效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值