3.使用临时表实现 GROUP BY
MySQL 在进行 GROUP BY 操作的时候要想利用所有,必须满足 GROUP BY 的字段必须同时存放于同一个索引中,且该索引是一个有序索引(如 Hash 索引就不能满足要求)。而且,并不只是如此,是否能够利用索引来实现 GROUP BY 还与使用的聚合函数也有关系。
前面两种 GROUP BY 的实现方式都是在有可以利用的索引的时候使用的,当 MySQL Query Optimizer 无法找到合适的索引可以利用的时候,就不得不先读取需要的数据,然后通过临时表来完成 GROUP BY 操作。
1 sky@localhost: example09:02:40>EXPLAIN2 3 ->SELECTmax(gmt_create)4 5 ->FROMgroup_message6 7 ->WHEREgroup_id>1andgroup_id<108 9 ->GROUPBYuser_id\G10 11 ***************************1. row***************************12 13 id:114 15 select_type: SIMPLE16 17 table: group_message18 19 type: range20 21 possible_keys: idx_group_message_gid_uid,idx_gid_uid_gc22 23 key: idx_gid_uid_gc24 25 key_len:426 27 ref:NULL28 29 rows:3230 31 Extra: Usingwhere; Usingindex; Usingtemporary; Using filesort
这次的执行计划非常明显的告诉我们 MySQL 通过索引找到了我们需要的数据,然后创建了临时表,又进行了排序操作,才得到我们需要的 GROUP BY 结果。整个执行过程大概如下图所展示:
当 MySQL Query Optimizer 发现仅仅通过索引扫描并不能直接得到 GROUP BY 的结果之后,他就不得不选择通过使用临时表然后再排序的方式来实现 GROUP BY了。
在这样示例中即是这样的情况。 group_id 并不是一个常量条件,而是一个范围,而且 GROUP BY 字段为 user_id。所以 MySQL 无法根据索引的顺序来帮助 GROUP BY 的实现,只能先通过索引范围扫描得到需要的数据,然后将数据存入临时表,然后再进行排序和分组操作来完成 GROUP BY。