可以这样改一下:SELECT c1,c3 FROM t1 where c3='a' GROUP BY c1, c2
下面这个例子不能使用松散索引扫描
SELECT c1,c3 FROM t1 where c3='a' GROUP BY c1, c2
为什么松散索引扫描的效率会很高?
答:因为在没有WHERE 子句,也就是必须经过全索引扫描的时候, 松散索引扫描需要读取的键值数量与分组的组数量一样多,也就是说比实际存在的键值数目要少很多。而在WHERE 子句包含范围判断式或者等值表达式的时候, 松散索引扫描查找满足范围条件的每个组的第1 个关键字,并且再次读取尽可能最少数量的关键字。
2、使用紧凑索引扫描(Tight index scan)实现 GROUP BY
紧凑索引扫描实现 GROUP BY 和松散索引扫描的区别主要在于:
紧凑索引扫描需要在扫描索引的时候,读取所有满足条件的索引键,然后再根据读取出的数据来完成 GROUP BY 操作得到相应结果。
这时候的执行计划的 Extra 信息中已经没有“Using index for group-by”了,但并不是说 MySQL 的 GROUP BY 操作并不是通过索引完成的,只不过是需要访问 WHERE 条件所限定的所有索引键信息之后才能得出结果。这就是通过紧凑索引扫描来实现 GROUP BY 的执行计划输出信息。
在 MySQL 中,MySQL Query Optimizer 首先会选择尝试通过松散索引扫描来实现 GROUP BY 操作,当发现某些情况无法满足松散索引扫描实现 GROUP BY 的要求之后,才会尝试通过紧凑索引扫描来实现。
当 GROUP BY 条件字段并不连续或者不是索引前缀部分的时候,MySQL Query Optimizer 无法使用松散索引扫描。
这时检查where 中的条件字段是否有索引的前缀部分,如果有此前缀部分,且该部分是一个常量,且与group by 后的字段组合起来成为一个连续的索引。这时按紧凑索引扫描。
SELECT max(gmt_create)
FROM group_message
WHERE group_id = 2
GROUP BY user_id
需读取group_id=2的所有数据,然后在读取的数据中完成group by操作得到结果。(这里group by 字段并不是一个连续索引,正好where 中group_id正好弥补缺失的索引键,又恰好是一个常量,因此使用紧凑索引扫描)
group_id user_id 这个顺序是可以使用该索引。如果连接的顺序不符合索引的“最左前缀”原则,则不使用紧凑索引扫描。
以下例子使用紧凑索引扫描
GROUP BY中有一个差距,但已经由条件user_id = 1覆盖。
explain
SELECT group_id,gmt_create
FROM group_message
WHERE user_id = 1 GROUP BY group_id,gmt_create
GROUP BY不以关键字的第1个元素开始,但是有一个条件提供该元素的常量
explain
SELECT group_id,gmt_create
FROM group_message
WHERE group_id = 1 GROUP BY user_id,gmt_create
下面的例子都不使用紧凑索引扫描
user_id,gmt_create 连接起来并不符合索引“最左前缀”原则










