mySQL 8 中带有排序依据、限制和括号的奇怪行为
Strange behavior in mySQL 8 with order by, limit and parentheses
假设我有一个 table 具有以下值
我执行以下查询并获得附加结果
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 以及它们如何处理包含按 and/or 限制操作排序的 UNION 查询。可能使用了太多括号,无论它们是否属于并集。我们的一些 SQL 是生成的,因此在某些情况下,引擎可能会自动添加括号,以预期结果可能会用于更大的联合查询。反正。我离题了。
EDIT/UPDATE:
正如 nbk 和 nick 指出的那样,括号的使用无论在这种情况下看起来多么无害,都会导致 MySQL 将其作为子查询处理。但是,以下查询实际上有效,这似乎与给出的解释相反。
SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3;
现在这是子查询的完整形式,但它似乎确实在子查询中应用了排序,然后限制了结果。
编辑 2:
跟进 Nick 的回复。是的,这是一个实际查询的示例,为了清晰起见,它已被简化并使用模拟数据来防止泄露敏感的真实数据。
我想我对原始问题的回答基本上是 "MySQL has decided to optimize this as a subquery and therefore ignore the ORDER BY"。这让我很头疼。为什么以下查询在功能上看起来是等同的,但处理方式不同。
(SELECT * FROM testvalues ORDER BY textval) LIMIT 3;
SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3;
在 subqueries/derived 表内排序不影响最终输出;这些行由外层ORDER BY
子句仅 排序。由于您没有,最后一个查询中结果的排序是不确定的。如果写成
就可以正常工作
(SELECT * FROM testvalues) ORDER BY textval LIMIT 3;
中对此行为进行了描述
请注意,当您尝试 "real" 子查询时,即
SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3
优化器将传播 ORDER BY
子句,因为它满足 manual:
中描述的条件
The optimizer propagates an ORDER BY clause in a derived table or
view reference to the outer query block if these conditions are all
true:
The outer query is not grouped or aggregated.
The outer query does not specify DISTINCT, HAVING, or ORDER BY.
The outer query has this derived table or view reference as the only source in the FROM clause.
当这些条件不成立时:
Otherwise, the optimizer ignores the ORDER BY clause.
正如这里所说的数百次,你的括号使它成为一个子查询,因此成为一个 table 并且为此:
A "table" 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.
来源
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;
numval | textval
-----: | :------
1 | a
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;
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra
-: | :---------- | :--------- | :--------- | :--- | :------------ | :--- | :------ | :--- | ---: | -------: | :-------------
1 | SIMPLE | testvalues | null | ALL | null | null | null | null | 8 | 100.00 | Using filesort
db<>fiddle here
假设我有一个 table 具有以下值
我执行以下查询并获得附加结果
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 以及它们如何处理包含按 and/or 限制操作排序的 UNION 查询。可能使用了太多括号,无论它们是否属于并集。我们的一些 SQL 是生成的,因此在某些情况下,引擎可能会自动添加括号,以预期结果可能会用于更大的联合查询。反正。我离题了。
EDIT/UPDATE:
正如 nbk 和 nick 指出的那样,括号的使用无论在这种情况下看起来多么无害,都会导致 MySQL 将其作为子查询处理。但是,以下查询实际上有效,这似乎与给出的解释相反。
SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3;
现在这是子查询的完整形式,但它似乎确实在子查询中应用了排序,然后限制了结果。
编辑 2:
跟进 Nick 的回复。是的,这是一个实际查询的示例,为了清晰起见,它已被简化并使用模拟数据来防止泄露敏感的真实数据。
我想我对原始问题的回答基本上是 "MySQL has decided to optimize this as a subquery and therefore ignore the ORDER BY"。这让我很头疼。为什么以下查询在功能上看起来是等同的,但处理方式不同。
(SELECT * FROM testvalues ORDER BY textval) LIMIT 3;
SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3;
在 subqueries/derived 表内排序不影响最终输出;这些行由外层ORDER BY
子句仅 排序。由于您没有,最后一个查询中结果的排序是不确定的。如果写成
(SELECT * FROM testvalues) ORDER BY textval LIMIT 3;
中对此行为进行了描述
请注意,当您尝试 "real" 子查询时,即
SELECT root.* FROM (SELECT * FROM testvalues ORDER BY textval) AS root LIMIT 3
优化器将传播 ORDER BY
子句,因为它满足 manual:
The optimizer propagates an ORDER BY clause in a derived table or view reference to the outer query block if these conditions are all true:
The outer query is not grouped or aggregated.
The outer query does not specify DISTINCT, HAVING, or ORDER BY.
The outer query has this derived table or view reference as the only source in the FROM clause.
当这些条件不成立时:
Otherwise, the optimizer ignores the ORDER BY clause.
正如这里所说的数百次,你的括号使它成为一个子查询,因此成为一个 table 并且为此:
A "table" 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.
来源
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;
numval | textval -----: | :------ 1 | a 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;
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra -: | :---------- | :--------- | :--------- | :--- | :------------ | :--- | :------ | :--- | ---: | -------: | :------------- 1 | SIMPLE | testvalues | null | ALL | null | null | null | null | 8 | 100.00 | Using filesort
db<>fiddle here