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操作 。这种方式在某些情况下可以避免创建临时表,从而提高查询效率