作者:Chaithra Gopalareddy 译:徐轶韬
在MySQL中,曾经 GROUP BY 也用于提供排序。如果查询指定了GROUP BY,则结果的排序就像查询中存在 ORDER BY 一样。

MySQL在这里隐式地对GROUP BY的结果进行排序(即没有对GROUP BY
列指定ASC
或DESC
)。
MySQL还支持使用GROUP BY进行显式排序(即通过对GROUP BY
列使用显式ASC
或DESC
)。
这在8.0中已经改变,因为它不再支持GROUP BY的隐式或显式排序。在这篇博文中,我将解释为什么发生这种变化,以及为这种变化所做的前期工作。
MySQL中的GROUP BY
要对一组数据进行分组,MySQL优化器会选择不同的方法。其中之一是分组之前对数据排序。这使得连续分组变得很容易。如果有一个索引可用于获取排序的数据,那么使用它的成本会非常低廉。如果没有索引,MySQL优化器仍然可以决定在分组之前进行外部(filesort)排序。

如示例所示,在向表中添加索引之前,MySQL使用外部排序来执行GROUP BY。对于该查询,我使用SQL_BIG_RESULT强制执行该计划(因为MySQL不会为这个数据集选择此计划)。但MySQL会使用此计划在没有索引的情况下进行分组以获取已排序的数据行,并且由于存在大量组,使用临时表会变得成本过高。添加索引后,它会使用索引来执行GROUP BY。
但是在分组之前排序并不是必须的。优化器可以决定使用临时表来执行此操作。此表中的每一行都是一个分组的行,随着每一行的进入,与该表中该组对应的行将被更新。这种情况不需要排序,但由于预计MySQL中的GROUP BY将进行排序,因此会强制对分组数据进行排序。

在示例查询中,我们看到虽然使用了临时表,但MySQL仍然进行外部排序。用户必须显式指定ORDER BY NULL才能让MySQL知道GROUP BY不需要排序。因此需要一个非标准(ORDER BY NULL)语法来抵消另一个非标准扩展(GROUP BY排序)的影响。现在我们已经消除了这种混乱,它更加清晰明了。
删除GROUP BY的隐式排序
不久前,我试图修复bug71804。报告者希望MySQL在执行GROUP BY时不做这种不必要的文件排序。尝试为bug制作补丁时,让我们意识到优化这种特殊情况并不是很简单,因为GROUP BY提供隐式和显式排序。因此,我们的结论是,在进行优化之前,我们应该重构与GROUP BY相关的代码。。
这样做的第一步是删除GROUP BY的隐式排序。正如在用户手册中所提到的那样,决定在一段时间后删除对它的支持。它已作为8.0中降序索引功能的一部分实现。

如上例所示,不对查询执行排序。分组数据不会在最终结果中排序。如果用户需要对数据排序,则必须在查询中指定ORDER BY。
在MySQL 5.7及更低版本中,用户在手册中找到以下警告。
“ GROUP BY
默认情况下隐式排序(即,没有ASC
或DESC
指示符
)。但是,不推荐依赖于隐式GROUP BY
排序(即,在没有ASC
或DESC
指示符的情况下GROUP BY
)或显式GROUP BY排序
(即,通过对列使用显式ASC
或DESC
指示符GROUP BY
)。要生成给定的排序顺序,请使用 ORDER BY
子句。“
删除GROUP BY的显式排序
当谈到删除显式排序时,遇到点小麻烦。我们无法删除它,除非MySQL支持ORDER BY进行ROLLUP。MySQL 5.7及更早版本中不允许使用ORDER BY进行ROLLUP。因此,作为替代方案,用户将使用GROUP BY ASC DESC通过ROLLUP获取排序数据(尽管排序非常严格,超级聚合行总是放在用于计算ASC的行之后,反之亦然,用于DESC) 。在删除GROUP BY的显式排序支持之前,我们必须解除此限制。
MySQL现在允许ORDER BY进行ROLLUP。我已经在https://mysqlserverteam.com/improvements-to-rollup-in-mysql/详细解释了如何使用这种改进。正如在同一篇博客中所解释的,如果用户想要与MySQL 5.7 for ROLLUP完全相同的NULL排序顺序,他们应该使用GROUPING()函数以简单的方式重新编写查询。
所以简而言之,我们已经做了以下事情作为删除GROUP BY的显式排序的前期准备。
1.添加GROUPING()函数
2.删除GROUP BY的隐式排序
3.允许ORDER BY进行ROLLUP
最后,我们在MySQL 8.0.13中删除了GROUP BY的显式排序。
我们在一段时间后询问了社区意见。我们的结论是,知道MySQL提供的这个非标准扩展的用户可以接受它的消失。
结论
虽然我们在修复bug71804之前仍有一些工作要做,但我们很高兴我们完成了这项工作。请让我们知道您的想法。
感谢您使用MySQL!




