MySQL/MariaDB - 按内部子查询排序

Posted

技术标签:

【中文标题】MySQL/MariaDB - 按内部子查询排序【英文标题】:MySQL/MariaDB - order by inside subquery 【发布时间】:2014-12-09 22:30:14 【问题描述】:

多年来,我在 mysql 5.5(或以前的版本)中使用了以下查询,没有任何问题:

SELECT t2.Code from (select Country.Code from Country order by Country.Code desc ) AS t2;

结果的顺序总是按我的需要降序。

上周,我刚刚迁移到一个新的 MySQL 版本(实际上,我迁移到了 MariaDB 10.0.14),现在使用相同数据库的相同查询不再按降序排序。是升序排序的(或者是自然排序,其实不确定)。

那么,谁能告诉我这是一个错误,还是最近版本的 MySQL/MariaDB 的行为发生了变化?

【问题讨论】:

可能相关:mariadb.com/kb/en/mariadb/… 【参考方案1】:

经过一番挖掘,我可以确认您的两种情况:

MySQL 5.1 确实在子查询中应用了ORDER BY

Linux 上的 MariaDB 5.5.39 在未提供 LIMIT 时在子查询中应用 ORDER BY。它确实在给出相应的LIMIT 时正确地应用了订单:

SELECT t2.Code 
FROM (
  SELECT Country.Code FROM Country ORDER BY Country.Code DESC LIMIT 2
) AS t2;

没有LIMIT,就没有充分的理由在子查询中应用排序。它可以等效地应用于外部查询。

记录的行为:

事实证明,MariaDB has documented this behavior 并没有被视为错误:

根据 SQL 标准,“表”(以及 FROM 子句中的子查询)是一组无序的行。表中的行(或FROM 子句中的子查询)没有任何特定的顺序。这就是优化器可以忽略您指定的ORDER BY 子句的原因。事实上,SQL 标准甚至不允许ORDER BY 子句出现在这个子查询中(我们允许它,因为ORDER BY ... LIMIT ... 改变了结果、行集,而不仅仅是它们的顺序)。

您需要将FROM 子句中的子查询视为一组未指定和未定义顺序的行,并将ORDER BY 放在***SELECT 上。

因此 MariaDB 还建议在最外层的查询中应用 ORDER BY,或在必要时使用 LIMIT

注意:我目前无法访问正确的 MySQL 5.5 或 5.6 来确认那里的行为是否相同(并且 SQLFiddle.com 出现故障)。 Comments on the original bug report(作为非错误关闭)表明 MySQL 5.6 的行为方式可能与 MariaDB 相同。

【讨论】:

非常感谢。我将 order by 应用于最外层的查询,它现在运行良好。 @Michael,order by典型不适用于子查询,不是吗?我认为任何数据库都不能保证这种排序。 @Pacerier 如引用的文档中所述“SQL 标准甚至不允许 ORDER BY 子句出现在此子查询中”,因此大多数 RDBMS 可能不会允许它. 不幸的是,至少对于 MySQL 5.5,select distinct / order by / limitselect distinct from (select order by) limit 慢得多 - 有几百万行,差异在 1000 倍左右。 "没有充分的理由在子查询中应用排序。它可以等效地应用于外部查询"废话。例如:要为每个组的某个列选择最大值或最小值,在 MySQL 中您应该能够:SELECT t1.* FROM (SELECT * FROM table ORDER BY value_col DESC) AS t1 GROUP BY group_col 为每个 group_col 获取最大值 value_col。当我输入 ORDER BY 时,我希望数据库对其进行排序,无论他是否认为这是个好主意。【参考方案2】:

在较新版本的 MySQL 和 MariaDB 中,您可以通过应用 LIMIT 在子查询中强制执行 ORDER BY。如果您不想限制行数,请使用最大的 BIGINT 数作为 LIMIT。

这有时会派上用场,例如,当需要按所需顺序生成子查询时,例如应用行号。

【讨论】:

以上是关于MySQL/MariaDB - 按内部子查询排序的主要内容,如果未能解决你的问题,请参考以下文章

按 Group_concat 内部排序

使用 Spring JPA 规范按子查询排序

MySQL/MariaDB查询执行路径

如何仅在没有子查询的 UNION ALL 中按一个查询排序

如何采用按单独列排序的 DISTINCT ON 子查询并使其快速?

数据表子表单按列排序