前言

在MySQL的老版本(MySQL5.7及以前)中, GROUP BY xxx 等同于 GROUP BY xxx ORDER BY xxx,在 GROUP BY 的同时,会自带排序的效果。包括也可以手动排序 GROUP BY xxx DESC,等同于 GROUP BY xxx ORDER BY xxx DESC

MySQL8.0 版本删除了隐式排序,包括显示排序也报错。在升级到MySQL8.0之后,由于缺少了隐式排序,可能会造成查询结果返回的顺序不稳定,造成结果不满足预期。

问题现象

  1. aliyun PolarDB MySQL 版 8.0.1.1.40版本,在DMS查询时,返回的顺序稳定
  2. 在程序JDBC查询时(连接的集群地址),返回的结果多次查询顺序不一致。

由于我们使用的是PolarDB 8.0+,首先开始怀疑是不是aliyun做了什么操作,查到他们的更新日志:https://help.aliyun.com/zh/polardb/polardb-for-mysql/polardb-for-mysql-8-0-1,发现他们在8.0版本中,将隐式排序的功能又加了回来,那么更进一步证明问题出现在数据库层面了。

有了上面的分析和更新日志,我们又进行了接下来的几次测试,进一步缩小问题范围,定位问题的根本原因。

  1. 通过MySQL命令行,连接到集群地址,返回的结果多次查询顺序不一致。
  2. 通过MySQL命令行,连接到主节点地址,返回的顺序稳定
  3. 通过MySQL命令行,连接到只读从节点地址,返回的结果多次查询顺序不一致。

通过咨询aliyun工程师,了解到DMS默认是直连主库的,结合上述三个执行结果来看,似乎问题出现在了从库,当请求从从库执行来看,顺序总是不一致。

有了上述的结论,通过进一步咨询aliyun的工程师,最终定位到问题是因为其中有台从库开启了并行查询,导致了返回顺序会存在多次查询不一致的问题。


总结

虽然最终定位到了原因是并行查询导致的问题,但是我还是认为,既然aliyun的版本公告中已经说明了加回了 GROUP BY 隐式排序功能,那么不管是并行查询还是什么原因,就算是在 MySQL Server层进行汇总排序,也需要保证最终结果和预期一致,否则会造成使用方的预期不满足。
其次,对于隐式排序肯定不能进行依赖,还是回归到程序上,不论什么情况肯定不能依赖于约定俗成的一些功能,应该强依赖自己写下的指令,比如手动指定 ORDER BY 比事后去分析还是好很多。但整个过程还是学习到不少东西,还是有一定收获的。

扩展

旧版本为什么会有排序?

因为要对数据进行分组的话,本身也会对分组前的数据进行排序,降低数据复杂度,所以原始数据本身就已经有序了。
其次,如果是 GROUP BY 的一个索引字段,那么索引字段本身是 B+ Trree,本身也是有序的,且平时 GROUP BY的字段大概率是有索引的(否则效率太低了),所以绝大部分情况下,旧版本的 GROUP BY 就为我们保留了排序。

为什么要删除隐式排序?

会造成预期外的结果,比如没有明确指定