-1

假设我有一个包含以下值的表

在此处输入图像描述

我执行以下查询并获得附加的结果

SELECT * FROM testvalues ORDER BY textval;

在此处输入图像描述

到目前为止一切都很好。我现在将添加一个 LIMIT 语句。

SELECT * FROM testvalues ORDER BY textval LIMIT 3;

在此处输入图像描述

仍然一切看起来都很好。但是请注意当我在查询中添加括号时会发生什么。

(SELECT * FROM testvalues ORDER BY textval) LIMIT 3;

在此处输入图像描述

关于括号为什么会导致顺序不正确的任何想法。似乎使用括号仅用于确保在应用限制之前完成内部查询并因此对其进行排序。但似乎它会导致应用限制并完全丢弃排序。这是一个错误吗?一个已知的错误?我没有看到任何报道。

这是因为最近从 MySQL5.5 升级到 MySQL8 以及它们如何处理包含 order by 和/或 limit 操作的 UNION 查询。无论它们是否是联合的一部分,都可能使用了太多括号。我们的一些 SQL 是生成的,因此在某些情况下,引擎可能会自动添加括号,以预测结果可能会用于更大的联合查询。反正。我偏离了核心问题。

编辑/更新:

正如 nbk 和 nick 所指出的,括号的使用,无论在这种情况下看起来多么无害,都会导致 MySQL 将其作为子查询来处理。但是,以下查询实际上有效,这似乎与给出的解释相反。

SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3;

在此处输入图像描述

现在这是子查询的完整形式,但是看起来它确实在子查询中应用了排序,然后限制了结果。

编辑2:

跟进尼克的回应。是的,这是一个实际查询的示例,为了清楚起见,它已经过简化,并使用模拟数据来防止泄露敏感的真实数据。

我想我对原始问题的回答基本上是“MySQL 已决定将其优化为子查询,因此忽略 ORDER BY”。这让我很头疼。为什么以下查询在功能上看起来相同时处理方式不同。

(SELECT * FROM testvalues ORDER BY textval) LIMIT 3;

SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3;
4

2 回答 2

2

在子查询/派生表中排序不会影响最终输出;这些行按外部级别ORDER BY子句排序。由于您没有,因此最后一个查询中结果的顺序是不确定的。如果写成,它将正常工作

(SELECT * FROM testvalues) ORDER BY textval LIMIT 3;

MariaDB 知识库中有关于这种行为的描述。

请注意,当您尝试“真实”子查询时,即

SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3

优化器将传播该ORDER BY子句,因为它满足手册中描述的条件:

如果这些条件都为真,优化器将派生表或视图引用中的 ORDER BY 子句传播到外部查询块:

  • 外部查询未分组或聚合。

  • 外部查询未指定 DISTINCT、HAVING 或 ORDER BY。

  • 外部查询将此派生表或视图引用作为 FROM 子句中的唯一来源。

当这些条件不成立时:

否则,优化器会忽略 ORDER BY 子句。

于 2019-12-05T20:42:36.390 回答
1

正如这里所说的数百次,你的括号使它成为一个子查询,因此是一个表,为此:

根据 SQL 标准的“表” - 一组无序的行。表中的行(或 FROM 子句中的子查询)没有任何特定的顺序。这就是优化器可以忽略您指定的 ORDER BY 子句的原因。

来源

https://mariadb.com/kb/en/library/why-is-order-by-in-a-from-subquery-ignored/

但是如果当然也适用于mysql,它也是有效的。

我个人认为你的问题得到了回答。

但是对于你的第二个问题。

您应该始终查看 mysql 的解释功能,因为您可以看到它在这种情况下使用filesort

CREATE TABLE `testvalues` (
numval INT ,
`textval` VARchar(2) );
INSERT INTO `testvalues` (numval,textval)
VALUES (1,'a'),(6,'f'),(7,'g'),(4,'d'),(2,'b'),(5,'e'),(8,'h'),(3,'c');
select * From testvalues;
数字 | 文本值
-----: | :------
     1 | 一种      
     6 | F      
     7 | G      
     4 | d      
     2 | b      
     5 | e      
     8 | H      
     3 | C      
EXPLAIN SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3;
编号 | 选择类型 | 表| 隔断 | 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 过滤 | 额外的         
-: | :------------ | :--------- | :--------- | :--- | :------------ | :--- | :-------- | :--- | ---: | --------: | :-------------
 1 | 简单 | 测试值 |        | 全部 |           | |     | | 8 | 100.00 | 使用文件排序

db<>在这里摆弄

于 2019-12-05T20:42:37.953 回答