MySQL中GROUP BY隐式排序是什么概念呢? 主要是其它RDBMS没有这样的概念,若是没有认真了解过概念,对这个概念会感受有点困惑,咱们先来看看官方文档的介绍:mysql
官方文档MySQL 5.7 Reference Manual中的“.2.1.14 ORDER BY Optimization”章节有以下介绍:sql
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子句。app
从MySQL 8.0开始,GROUP BY字段再也不支持隐式排序. 官方文档MySQL 8.0 Reference Manual中“8.2.1.16 ORDER BY Optimization”章节有以下介绍:ide
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.sqlserver
那么来看看MySQL的GROUP BY隐式排序(GROUP BY sorted implicitly)吧。咱们用“Removal of implicit and explicit sorting for GROUP BY”这篇博客中的例子。测试
下面实验环境为MySQL 5.6.41()spa
mysql> select version() from dual;
+------------+
| version() |
+------------+
| 5.6.41-log |
+------------+
1 row in set (0.00 sec)
mysql> CREATE TABLE t (id INTEGER, cnt INTEGER);
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO t VALUES (4,1),(3,2),(1,4),(2,2),(1,1),(1,5),(2,6),(2,1),(1,3),(3,4),(4,5),(3,6);
Query OK, 12 rows affected (0.00 sec)
Records: 12 Duplicates: 0 Warnings: 0
#MySQL在这里隐式地对GROUP BY的结果进行排序(即在缺乏GROUP BY列的ASC或DESC指示符的状况下)。code
mysql> SELECT id, SUM(cnt) FROM t GROUP BY id; --GROUP BY隐式排序
+------+----------+
| id | SUM(cnt) |
+------+----------+
| 1 | 13 |
| 2 | 9 |
| 3 | 12 |
| 4 | 6 |
+------+----------+
4 rows in set (0.00 sec)
MySQL还支持使用GROUP BY进行显式排序(即经过对GROUP BY列使用显式ASC或DESC指示符)orm
mysql> SELECT id, SUM(cnt) FROM t GROUP BY id DESC; --GROUP BY显式排序
+------+----------+
| id | SUM(cnt) |
+------+----------+
| 4 | 6 |
| 3 | 12 |
| 2 | 9 |
| 1 | 13 |
+------+----------+
4 rows in set (0.00 sec)
从MySQL8.0开始,MySQL再也不支持GROUP BY的隐式或显示排序,以下所示:
#下面实验环境为MySQL 8.0.18
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.18 |
+-----------+
1 row in set (0.00 sec)
mysql> CREATE TABLE t (id INTEGER, cnt INTEGER);
Query OK, 0 rows affected (0.39 sec)
mysql> INSERT INTO t VALUES (4,1),(3,2),(1,4),(2,2),(1,1),(1,5),(2,6),(2,1),(1,3),(3,4),(4,5),(3,6);
Query OK, 12 rows affected (0.10 sec)
Records: 12 Duplicates: 0 Warnings: 0
mysql> SELECT id, SUM(cnt) FROM t GROUP BY id;
+------+----------+
| id | SUM(cnt) |
+------+----------+
| 4 | 6 |
| 3 | 12 |
| 1 | 13 |
| 2 | 9 |
+------+----------+
4 rows in set (0.00 sec)
mysql> SELECT id, SUM(cnt) FROM t GROUP BY id DESC;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DESC' at line 1
如上所示,GROUP BY隐式排序不支持了,在MySQL 8.0中,上面测试例子是无序的。GROUP BY显示排序则直接报错。因此若是有数据库从MySQL 5.7或以前的版本,迁移升级到MySQL 8的话,就须要特别留意这个问题了。正确的作法应该是GROUP BY .. ORDER BY 这种操做。以下所示:
mysql> SELECT id, SUM(cnt) FROM t GROUP BY id
-> ORDER BY id;
+------+----------+
| id | SUM(cnt) |
+------+----------+
| 1 | 13 |
| 2 | 9 |
| 3 | 12 |
| 4 | 6 |
+------+----------+
4 rows in set (0.00 sec)
mysql>
MySQL 8.0.13中删除了GROUP BY的显式排序。至于为何MySQL 8.0再也不支持GROUP BY的隐式排序和显示排序,这篇文章“Removal of implicit and explicit sorting for GROUP BY”已经有详细的介绍,这里不多此一举了。
参考资料:
https://mysqlserverteam.com/removal-of-implicit-and-explicit-sorting-for-group-by/