Group by隐式排序,一个优美的BUG,推荐深入linux内核架构

核对代码时我们发现,老版本Select语句中只是用到了Group by分组,也没有用到order by排序,有点蒙,为啥没用order by却排了序?查资料后得知,在MySQL8.0版本前是存在Group by隐式排序的! 就是说在我们使用分组(Group by)时,如:select * from T group by appName; 会默认按照appName正序排序,相当于select * from T group by appName order by appName;,倒排同理:select * from T group by appName desc; 可见,MySQL在8.0版本前的分组查询中,偷偷加上了排序操作。

纳尼?MySQL还有这种操作?快找一下官方文档对Group by隐式排序的介绍:

[](

)官方文档


官方文档MySQL 5.7 Reference Manual中的“2.1.14 ORDER BY Optimization”章节有如下介绍:

GROUP BY implicitly sorts by default (that is, in the absence of

【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】

浏览器打开:qq.cn.hn/FTf 免费领取

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.

google翻译:默认情况下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.

google翻译:以前(MySQL 5.7及更低版本),GROUP BY在某些条件下隐式排序。 在MySQL 8.0中,不再发生这种情况,因此不再需要在末尾指定ORDER BY NULL来抑制隐式排序(如前所述)。 但是,查询结果可能与以前的MySQL版本不同。 要产生给定的排序顺序,请提供ORDER BY子句

陈哈哈:“哦,这么看来开发老版本的同事是没用Order by,直接用了隐式排序。年轻人,不讲武德啊!!”

小王(小声):“哈哥,这模块之前好像是你负责的。”

陈哈哈(老脸一红):???

陈哈哈:“咳咳,这MySQL8.0团队不讲武德,给我挖坑!”

在这里插入图片描述

好了,接下来我们用测试数据演示一下

[](

)数据测试


下面是表T测试数据,无序

mysql> SELECT pid,appName from T;

±-------±------------------------+

| pid | appName |

±-------±------------------------+

| 1 | Dock Sound Redirector |

| 2 | Blues Music station |

| 3 | usb tether TRIAL |

| 4 | Il vero test del QI |

| 5 | FlightTime Calculator |

| 6 | ZX Spectrum Emulator |

| 7 | The City Dress Up |

±-------±------------------------+

7 rows in set (0.00 sec)

实验1:(MySQL版本:5.7.24)

– 隐式排序

mysql> SELECT pid,appName from T group by appName;

±-------±------------------------+

| pid | appName |

±-------±------------------------+

| 2 | Blues Music station |

| 1 | Dock Sound Redirector |

| 5 | FlightTime Calculator |

| 4 | Il vero test del QI |

| 7 | The City Dress Up |

| 3 | usb tether TRIAL |

| 6 | ZX Spectrum Emulator |

±-------±------------------------+

7 rows in set (0.00 sec)

– 如上述隐式排序,相当于SELECT pid,appName from T group by appName asc 或 SELECT pid,appName from T group by appName order by appName asc;

– 显式排序,相当于SELECT pid,appName from T group by appName order by appName desc;

mysql> SELECT pid,appName from T group by appName desc;

±-------±------------------------+

| pid | appName |

±-------±------------------------+

| 6 | ZX Spectrum Emulator |

| 3 | usb tether TRIAL |

| 7 | The City Dress Up |

| 4 | Il vero test del QI |

| 5 | FlightTime Calculator |

| 1 | Dock Sound Redirector |

| 2 | Blues Music station |

±-------±------------------------+

7 rows in set (0.00 sec)

实验2:(MySQL版本:8.0.16)

mysql> SELECT pid,appName from T group by appName;

±-------±------------------------+

| pid | appName |

±-------±------------------------+

| 1 | Dock Sound Redirector |

| 2 | Blues Music station |

| 3 | usb tether TRIAL |

| 4 | Il vero test del QI |

| 5 | FlightTime Calculator |

| 6 | ZX Spectrum Emulator |

| 7 | The City Dress Up |

±-------±------------------------+

7 rows in set (0.00 sec)

mysql> SELECT pid,appName from T group by appName 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

如上所示,在MySQL 8.0中,GROUP BY隐式排序不支持了,上面测试例子是无序的。GROUP BY显示排序则直接报错。所以如果有数据库从MySQL 5.7或之前的版本,迁移升级到MySQL 8的话,就需要特别留意这个问题了。

[](

)二、隐式排序 - 起源(一个优美的BUG)

====================================================================================

最初为什么要用隐式排序呢?我们知道,要对一组数据进行分组,MySQL优化器会选择不同的方法。其中最有效的一种是分组之前对数据排序,降低数据复杂度,使得连续分组变得很容易。另外,如果可以Group by 一个索引字段来用于获取排序的数据,那么使用它的成本就非常低了(因为BTree索引是天然有序的)。而在实际操作中,Group by用到索引的频率很高。这么看,这确实是个很棒的主意!也可以说是留了一个优美的BUG

如下查询语句,用到了appName_idx索引,因此group by查询不需要排序,直接分组,高效。

– 有索引:appName_idx

mysql> EXPLAIN SELECT appName from 0122_csj_demo GROUP BY appName \G

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值