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

2021-11-20 00:00:00 sql subquery mariadb mysql sql-order-by

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

I used the following query with MySQL 5.5 (or previous versions) for years without any problems:

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

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

The order of the result was always descending as I needed.

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

Last week, I just migrated to a new MySQL Version (In fact, I migrated to MariaDB 10.0.14) and now the same query with the same database is not sorted descending anymore. It is sorted ascending (or sorted using the natural order, not sure in fact).

那么,有人能告诉我这是一个错误还是最近版本的 MySQL/MariaDB 行为的改变?

So, can somebody could tell me if this is a bug or if this is a change of the behaviour in recent versions of MySQL/MariaDB?

推荐答案

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

After a bit of digging, I can confirm both your scenarios:

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

MySQL 5.1 does apply the ORDER BY inside the subquery.

Linux 上的 MariaDB 5.5.39 不会在未提供 LIMIT 的子查询中应用 ORDER BY.当给出相应的 LIMIT 时,它确实正确地应用了顺序:

MariaDB 5.5.39 on Linux does not apply the ORDER BY inside the subquery when no LIMIT is supplied. It does however correctly apply the order when a corresponding LIMIT is given:

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

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

Without that LIMIT, there isn't a good reason to apply the sort inside the subquery. It can be equivalently applied to the outer query.

事实证明,MariaDB 已经记录了这种行为 并且它不被视为错误:

As it turns out, MariaDB has documented this behavior and it is not regarded as a bug:

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

A "table" (and subquery in the FROM clause too) is - according to the SQL standard - an unordered set of rows. Rows in a table (or in a subquery in the FROM clause) do not come in any specific order. That's why the optimizer can ignore the ORDER BY clause that you have specified. In fact, SQL standard does not even allow the ORDER BY clause to appear in this subquery (we allow it, because ORDER BY ... LIMIT ... changes the result, the set of rows, not only their order).

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

You need to treat the subquery in the FROM clause, as a set of rows in some unspecified and undefined order, and put the ORDER BY on the top-level SELECT.

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

So MariaDB also recommends applying the ORDER BY in the outermost query, or a LIMIT if necessary.

注意:我目前无法访问合适的 MySQL 5.5 或 5.6 来确认那里的行为是否相同(并且 SQLFiddle.com 出现故障).对原始错误报告的评论(关闭为 not-a-bug)表明 MySQL 5.6可能与 MariaDB 的行为方式相同.

Note: I don't currently have access to a proper MySQL 5.5 or 5.6 to confirm if the behavior is the same there (and SQLFiddle.com is malfunctioning). Comments on the original bug report (closed as not-a-bug) suggest that MySQL 5.6 probably behaves the same way as MariaDB.

相关文章