MySQL中 group by and distinct
- 在语义相同,有索引的情况下:group by和distinct都能使用索引,效率相同。
- 在语义相同,无索引的情况下:distinct效率高于group by。原因是 distinct 和 group by都会进行分组操作,但group by可能会进行排序,触发filesort,导致sql执行效率低下。
distinct
- 如果列具有NULL值,并且对该列使用DISTINCT子句,MySQL将保留一个NULL值,并删除其它的NULL值,因为DISTINCT子句将所有NULL值视为相同的值。
- 多列去重,则是合在一起一样才是需要去重的。
group by
- group by的原理是先对结果进行分组排序,然后返回每组中的第一条数据。且是根据group by的后接字段进行去重的。
MySQL8.0之前
默认会依据字段进行隐式排序。explain 下,Extra 是 Using temporary; Using filesort ,即:使用了临时表、进行了filesort(文件排序)
Group by会默认根据作用字段(Group by的后接字段)对结果进行排序。
- 在能利用索引的情况下,Group by不需要额外进行排序操作;
- 但当无法利用索引排序时,Mysql优化器就不得不选择通过使用临时表然后再排序的方式来实现GROUP BY了。
- 手动解决的方法:通过添加 order by null 来禁止隐式排序 且当结果集的大小超出系统设置临时表大小时,会将临时表数据copy到磁盘上面再进行操作,执行效率会变得极低。所以这会弃用掉(deprecated)
使用
- 如果只需要去重某个字段的值,可以使用 distinct 关键字。
- 如果需要对结果集进行分组计算和聚合操作,可以使用 group by 关键字,这里可以再用上 count having
索引扫描
group by and distinct 都基于分组操作,且都可以通过松散索引扫描、紧凑索引扫描。
松散索引扫描(Loose Index Scan)是MySQL在处理GROUP BY查询时的一种优化方法。
定义与原理
- 利用索引直接获取GROUP BY所需字段
- 不需扫描所有满足条件的索引键
- 使用关键字排序的索引类型,如BTREE
实现条件
- 查询在单一表上
- GROUP BY指定的所有列必须在同一索引中
执行效率
- 只读取少量数据完成操作
- 执行效率高,尤其当WHERE子句包含范围判断式时
与紧凑索引扫描对比
- 松散索引扫描读取的关键字数量与组数量一样多
- 紧凑索引扫描需连续定位到目标记录
MySQL的紧凑索引扫描(Tight Index Scan)是一种优化技术,用于在执行GROUP BY操作时提高查询效率。紧凑索引扫描可以分为两种形式:全索引扫描和范围索引扫描,具体取决于查询条件。
- 当MySQL的查询优化器在执行GROUP BY操作时,如果无法使用松散索引扫描(Loose Index Scan),则会考虑使用紧凑索引扫描
- 与松散索引扫描的主要区别在于,紧凑索引扫描需要读取所有满足条件的索引键,而松散索引扫描则可以跳过一些不必要的数据。
特点:它需要访问WHERE条件所限定的所有索引键信息,并填充搜索关键字中的“差距”,形成完整的索引前缀,从而完成GROUP BY操作 。这种方式在某些情况下可以避免创建临时表,从而提高查询效率