MySQL有关Group By的优化


我写了有关MySQL的loose index scan的相关博文(),后来我发现上次提到的那个优化方法中主要的目的就是实现loose index scan,而在执行计划的层面上看,Extra信息中应该是“Using index for group-by”。这样看来,可能MySQL在处理distinct时和group by用了同样的优化手段,即走索引,进行loose index scan。那么今天我研究了一下官方文档,发现确实如此。

其实对于group by来讲,最一般的实现方法就是进行一次全表扫描,将所有的group by的行按照顺序存放在一个temporary table中,然后在进行分组识别或者进行聚合操作。这样问题就是太复杂,时间上要好久,空间上的消耗也不小。这时,MySQL可以利用索引来优化group by。

这里就可以讲讲什么叫做loose index scan了,根据官方的定义,这种方法只需要扫描索引中的少部分数据,而不是所有满足where条件的数据,所以这个方法叫做loose index scan。

下面是什么情况下可以使用loose index scan的情况:

1 单一表查询

2 Group by中只有最左前缀列,没有其他列

3 只支持max和min聚合,而且,要聚合的列必须是group by中列所在的索引。

4 未被group by引用的索引其他部分必须是常量(这句我不是很理解)

5 不支持前缀索引。

假设t1(c1, c2, c3, c4)表有一个索引包括c1, c2, c3列,以下这些查询都是可以进行loose index scan的:

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;

这些都是抄的官方文档,正确性未完全验证。

下面这些SQL都没有办法使用loose index scan:

-- 因为聚合函数不是max或者min

SELECT c1, SUM(c2) FROM t1 GROUP BY c1;

-- 因为不符合最左前缀原则

SELECT c1, c2 FROM t1 GROUP BY c2, c3;

-- 查询涉及到了索引的一部分,紧跟group by中的列,但是没有常量等值语句,加上 WHERE c3 = const就好了

SELECT c1, c3 FROM t1 GROUP BY c1, c2;

另外一些聚合函数也是可以用到loose index scan的,比如:AVG(DISTINCT), SUM(DISTINCT), 和COUNT(DISTINCT)

以下这些语句也可以:

SELECT COUNT(DISTINCT c1), SUM(DISTINCT c1) FROM t1;

SELECT COUNT(DISTINCT c1, c2), COUNT(DISTINCT c2, c1) FROM t1;

很多语句都是从5.7的文档上摘抄下来的,正确性没有得到验证,虽说官方文档是权威,但是尽信书不如无书,以及纸上得来终觉浅,绝知此事须躬行,明天周末,我逐条测试,然后再更。

本文永久更新链接地址

相关内容