MySQL中GROUP BY隐式排序是什么概念呢?其它RDBMS没有这样的概念。
我们先来看看官方文档的介绍:
官方文档MySQL 5.7 Reference Manual中的“.2.1.14 ORDER BY Optimization”章节有如下介绍:
GROUP BY implicitly sorts by default (that is, in the absence of ASC or DESC designators for GROUP BY columns). However, relying on implicit GROUP BY sorting (that is, sorting in the absence of ASC or DESC designators) or explicit sorting for GROUP BY (that is, by using explicit ASC or DESC designators for GROUP BY columns) is deprecated. To produce a given sort order, provide an ORDER BY clause.
默认情况下GROUP BY隐式排序(即缺少GROUP BY列的ASC或DESC指示符)。但是,不推荐依赖于隐式GROUP BY排序(即在没有ASC或DESC指示符的情况下排序)或GROUP BY的显式排序(即,通过对GROUP BY列使用显式ASC或DESC指示符)。要生成给定的排序 ORDER,请提供ORDER BY子句。
从MySQL 8.0开始,GROUP BY字段不再支持隐式排序。
官方文档MySQL 8.0 Reference Manual中“8.2.1.16 ORDER BY Optimization”章节有如下介绍:
Previously (MySQL 5.7 and lower), GROUP BY sorted implicitly under certain conditions. In MySQL 8.0, that no longer occurs, so specifying ORDER BY NULL at the end to suppress implicit sorting (as was done previously) is no longer necessary. However, query results may differ from previous MySQL versions. To produce a given sort order, provide an ORDER BY clause.
之前的MySQL 5.7以及更低版本,GROUP BY在某些情况下隐式排序。在MySQL 8.0中,不再发生这种情况,因此不再需要在末尾指定ORDER BY NULL来抑制隐式排序(如前所述)。但是,查询结果可能与以前的MySQL版本不同。要产生给定的排序顺序,请提供ORDER BY子句。
那么来看看MySQL的GROUP BY隐式排序(GROUP BY sorted implicitly)吧。我们用“Removal of implicit and explicit sorting for GROUP BY”这篇博客中的例子。
#下面实验环境为MySQL 5.6.41()
mysql>selectversion() fromdual; +------------+|version() |+------------+|5.6.41-log|+------------+1rowinset (0.00sec) mysql>CREATETABLEt (idINTEGER, cntINTEGER); QueryOK, 0rowsaffected (0.04sec) mysql>INSERTINTOtVALUES (4,1),(3,2),(1,4),(2,2),(1,1),(1,5),(2,6),(2,1),(1,3),(3,4),(4,5),(3,6); QueryOK, 12rowsaffected (0.00sec) Records: 12Duplicates: 0Warnings: 0
MySQL在这里隐式地对GROUP BY的结果进行排序(即在缺少GROUP BY列的ASC或DESC指示符的情况下)。
mysql>SELECTid, SUM(cnt) FROMtGROUPBYid; --GROUPBY隐式排序|id|SUM(cnt) |+------+----------+|1|13||2|9||3|12||4|6|+------+----------+4rowsinset (0.00sec)
MySQL还支持使用GROUP BY进行显式排序(即通过对GROUP BY列使用显式ASC或DESC指示符)
mysql>SELECTid, SUM(cnt) FROMtGROUPBYidDESC; --GROUPBY显式排序+------+----------++------+----------+|4|6||3|12||2|9||1|13|+------+----------+4rowsinset (0.00sec)
从MySQL8.0开始,MySQL不再支持GROUP BY的隐式或显示排序,如下所示:
#下面实验环境为MySQL 8.0.18
mysql>selectversion(); +-----------+|version() |+-----------+|8.0.18|+-----------+1rowinset (0.00sec) mysql>CREATETABLEt (idINTEGER, cntINTEGER); QueryOK, 0rowsaffected (0.39sec) mysql>INSERTINTOtVALUES (4,1),(3,2),(1,4),(2,2),(1,1),(1,5),(2,6),(2,1),(1,3),(3,4),(4,5),(3,6); QueryOK, 12rowsaffected (0.10sec) Records: 12Duplicates: 0Warnings: 0mysql>SELECTid, SUM(cnt) FROMtGROUPBYid; +------+----------+|id|SUM(cnt) |+------+----------+|4|6||3|12||1|13||2|9|+------+----------+4rowsinset (0.00sec) mysql>SELECTid, SUM(cnt) FROMtGROUPBYidDESC; ERROR1064 (42000): YouhaveanerrorinyourSQLsyntax; checkthemanualthatcorrespondstoyourMySQLserverversionfortherightsyntaxtousenear'DESC'atline1
如上所示,GROUP BY隐式排序不支持了,在MySQL 8.0中,上面测试例子是无序的。GROUP BY显示排序则直接报错。所以如果有数据库从MySQL 5.7或之前的版本,迁移升级到MySQL 8的话,就需要特别留意这个问题了。正确的做法应该是GROUP BY .. ORDER BY 这种操作。如下所示:
mysql>SELECTid, SUM(cnt) FROMtGROUPBYid->ORDERBYid; +------+----------+|id|SUM(cnt) |+------+----------+|1|13||2|9||3|12||4|6|+------+----------+4rowsinset (0.00sec)