您的位置:首页 > 其它

group by 优化临时表

2015-11-11 16:39 363 查看


GROUP BY 优化之临时表

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

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

代码8-27
sky@localhost : example 09:02:40> EXPLAIN
-> SELECT max(gmt_create)
-> FROM group_message
-> WHERE group_id > 1 and group_id < 10
->  GROUP BY user_id\G


*************************** 1. row ***************************
id:   1
select_type: SIMPLE
table:    group_message
type:    range
possible_keys:  idx_group_message_gid_uid,idx_gid_uid_gc
key:    idx_gid_uid_gc
key_len: 4
ref:    NULL
rows:    32
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)的子句,大家可以尝试一下看会有什么效果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: