group by
group by一般分两种,一种是使用索引分组(又有松散的索引扫描和紧凑的索引扫描两种),一种使用临时表分组。其中走索引的分组时间消耗会小的多,所以我们应该尽量让sql走索引。
在MySQL8之前,分组默认是排序的,8之后不在排序。
索引分组
使用索引分组又有两种,分别是松散的索引扫描和紧凑的索引扫描。
在索引中的列是已经按照索引的顺序进行分组的数据。
松散的索引扫描
根据group by后面的列取出索引中对应的列,再根据where条件进行筛选。
紧凑的索引扫描
先根据where条件进行筛选,再取出索引中所有列中符合条件的行。
例子
- 查询语句是
select idc,min(name) from t3 group by idc
,因为查询和分组的字段存在索引idx_idc_name_id,所以会走索引。 - 查询语句是
select idc,min(name) from t3 group by name
,因为不存在以name为顺序分组的索引,所以不会走索引。 - 查询语句是
select id,name from t3 where idc=3 group by idc
,虽然不存在以name为顺序的索引,但是!!!where idc=3这个条件,限制了idc是相同的,当idc相同时,索引 idx_idc_name_id就是按照name分组的,因此这个语句依然会走索引。 - 查询语句是
select id,name from t3 where idc>2 group by name
,虽然where语句限定了idc>2这个条件,将数据分为了两部分>2,<=2。但是索引idx_idc_name_id是先按照idc分组,再按照name,最后按id分组,而我们的分组是只按照name,idc>2的数据里面id也是不一样的,所以没有走索引。 - 查询语句是
select id,name from t3 where idc>2 and idc<10 group by idc,name
,因为查询和分组的字段存在索引idx_idc_name_id,所以会走索引。
临时表分组
当没有索引时,会将所有需要的数据放到临时表中进行排序,然后读出返回给客户端。
distinct
distinct本质和group by是一样的,他的原理就是将所有的数据都分组,每个组里都是一样的数据,从每个组里去一条数据即可。
select distinct name from t3 where idc=3
和group是一样的。虽然不存在以name为顺序的索引,但是!!!where idc=3这个条件,限制了idc是相同的,当idc相同时,索引 idx_idc_name_id就是按照name分组的,因此这个语句依然会走索引。select distinct name from t3 where idc>3
虽然where语句限定了idc>2这个条件,将数据分为了两部分>2,<=2。但是索引idx_idc_name_id是先按照idc分组,再按照name,最后按id分组,而我们的分组是只按照name,idc>2的数据里面id也是不一样的,所以没有走索引。
总结
group by和order by一样,会不会走索引主要看select查询的字段,where限制条件和group by分组顺序。对select字段,where条件,order字段进行设计,尽可能的让排序走索引。