group by语句利用B+tree索引扫描时分为松散扫描、紧凑扫描两种情况:
Loose Index Scan(松散扫描)就是只需要对索引扫描时取出很小一部分键值就能完成整个sql所需数据的扫描,在where条件含有范围谓词或者无条件、sql语句利用索引就能完成查询的才能使用上松散扫描,用上松散索引扫描的有如下几种类型的语句:
表t1有c1,c2,c3,c4四个字段,index为(c1,c2,c3)
SELECT c1, c2 FROM t1 GROUP BY c1, c2;
SELECT DISTINCT c1, c2 FROM t1;
SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2;
SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2;
如上为官网给出能使用上松散索引扫描的情况,例如我这有个表有几百万的数据,建立了个拥有三个字段的索引。
mysql>select count(*) from history_20150425;
+--------------------+
| count(*)
+--------------------+
| 7880599
+--------------------+
共返回 1 行记录,花费 1734.54 ms.
mysql>alter table history_20150425 add index(dovalue,prevalue,taskid);
mysql> explain select dovalue,prevalue from history_20150425 group by dovalue,prevalue;
+----+-------------+----------------------------------+-------+---------------+--------------+---------+------+-------+------------
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------------------+-------+---------------+--------------+---------+------+-------+------------
| 1 | SIMPLE | history_20150425 | range | DoValue | DoValue | 8 | NULL | 65552 | Using index for group-by |
+----+-------------+----------------------------------+-------+---------------+--------------+---------+------+-------+------------
1 row in set (0.00 sec)
在extra列出现using index for group-by字样就表示利用上了loose index scan,其他情况就不贴出来了,有点浪费版面,可以自己按官网给出的类型自己试试。
Tight Index Scan(紧凑索引扫描),看完松散索引扫描就很好理解这个紧凑索引扫描了,就是需要读取所有数据才能满足查询所需数据。我们排除上面能用手松散扫描的情况就是紧凑扫描,下面依然是官方文档给出的例子:
例如表t1有c1,c2,c3,c4字段,index包含c1,c2,c3字段
SELECT c1, c2, c3 FROM t1 WHERE c2 = ‘a‘ GROUP BY c1, c3;
SELECT c1, c2, c3 FROM t1 WHERE c1 = ‘a‘ GROUP BY c2, c3;
像这两个只能挨个扫描完索引片段才能得到准确的数据的语句,就不能使用松散索引扫描,
group by假如不能使用索引扫描完成,在使用临时表分组时内部会进行order by排序再分组,这里可以用order by null强制取消内部排序操作。