MySQL 优化 GROUP BY-松散索引扫描与紧凑索引扫描

满足 GROUP BY 子句的最一般的方法是扫描整个表并创建一个新的临时表,表中每个组的所有行应为连续的,然后使用该临时表来找到组并应用累积函数 (如果有)。在某些情况中,MySQL 能够做得更好,即通过索引访问而不用创建临时表。

为 GROUP BY 使用索引的最重要的前提条件是所有 GROUP BY 列引用同一索引的属性,并且索引按顺序保存其关键字。是否用索引访问来代替临时表的使用还取决于在查询中使用了哪部分索引、为该部分指定的条件,以及选择的累积函数。

由于 GROUP BY 实际上也同样会进行排序操作,而且与 ORDER BY 相比,GROUP BY 主要只是多了排序之后的分组操作。当然,如果在分组的时候还使用了其他的一些聚合函数,那么还需要一些聚合函数的计算。所以,在 GROUP BY 的实现过程中,与 ORDER BY 一样也可以利用到索引。在 MySQL 中,GROUP BY 的实现同样有多种(三种)方式,其中有两种方式会利用现有的索引信息来完成 GROUP BY,另外一种为完全无法使用索引的场景下使用。下面我们分别针对这三种实现方式做一个分析。

1、使用松散索引扫描(Loose index scan)实现 GROUP BY

对 “松散索引扫描” 的定义,本人看了很多网上的介绍,都不甚明白。在此逻列如下:

定义 1:松散索引扫描,实际上就是当 MySQL 完全利用索引扫描来实现 GROUP BY 的时候,并不需要扫描所有满足条件的索引键即可完成操作得出结果。

定义 2:优化 Group By 最有效的办法是当可以直接使用索引来完全获取需要 group 的字段。使用这个访问方法时,MySQL 使用对关键字排序的索引的类型(比如 BTREE 索引)。这使得索引中用于 group 的字段不必完全涵盖 WHERE 条件中索引对应的 key。由于只包含索引中关键字的一部分,因此称为松散的索引扫描。

意思是索引中用于 group 的字段,没必要包含多列索引的全部字段。例如:有一个索引 idx(c1,c2,c3),那么 group by c1、group by c1,c2 这样 c1 或 c1、c2 都只是索引 idx 的一部分。要注意的是,索引中用于 group 的字段必须符合索引的 “最左前缀” 原则。group by c1,c3 是不会使用松散的索引扫描的

例如:

SELECT group_id,gmt_create
FROM group_message
WHERE user_id

Tag标签: