A correlated subquery is a subquery that contains a reference to a table that also appears in the outer query. 相关子查询是一个子查询,它包含对也出现在外部查询中的表的引用。For example:例如:
SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2 WHERE t2.column2 = t1.column2);
Notice that the subquery contains a reference to a column of 注意,子查询包含对t1
, even though the subquery's FROM
clause does not mention a table t1
. t1
列的引用,即使子查询的FROM
子句没有提到表t1
。So, MySQL looks outside the subquery, and finds 因此,MySQL在子查询外部查找,并在外部查询中找到t1
in the outer query.t1
。
Suppose that table 假设表t1
contains a row where column1 = 5
and column2 = 6
; meanwhile, table t2
contains a row where column1 = 5
and column2 = 7
. t1
包含一行,其中column1=5
,column2=6
;同时,表t2
包含一行,其中column1=5
,column2=7
。The simple expression 简单表达式... WHERE column1 = ANY (SELECT column1 FROM t2)
would be TRUE
, but in this example, the WHERE
clause within the subquery is FALSE
(because (5,6)
is not equal to (5,7)
), so the expression as a whole is FALSE
.... WHERE column1 = ANY (SELECT column1 FROM t2)
会成为TRUE
,但是在此示例中,子查询中的WHERE
子句是FALSE
(因为(5,6)
不等于(5,7)
,所以作为整体的表达式是FLASE
。)
Scoping rule:范围规则: MySQL evaluates from inside to outside. MySQL从内到外进行计算。For example:例如:
SELECT column1 FROM t1 AS x WHERE x.column1 = (SELECT column1 FROM t2 AS x WHERE x.column1 = (SELECT column1 FROM t3 WHERE x.column2 = t3.column1));
In this statement, 在此语句中,x.column2
must be a column in table t2
because SELECT column1 FROM t2 AS x ...
renames t2
. x.column2
必须是一个表t2
中的列,因为SELECT column1 FROM t2 AS x ...
重命名了t2
。It is not a column in table 它不是表t1
because SELECT column1 FROM t1 ...
is an outer query that is farther out.t1
中的列,因为SELECT column1 FROM t1 ...
是较远的外部查询。
Beginning with MySQL 8.0.24, the optimizer can transform a correlated scalar subquery to a derived table when the 从MySQL 8.0.24开始,优化器可以在启用优化器开关变量的subquery_to_derived
flag of the optimizer_switch
variable is enabled. subquery_to_derived
标志时,将相关标量子查询转换为派生表。Consider the query shown here:考虑下面显示的查询:
SELECT * FROM t1
WHERE ( SELECT a FROM t2
WHERE t2.a=t1.a ) > 0;
To avoid materializing several times for a given derived table, we can instead materialize—once—a derived table which adds a grouping on the join column from the table referenced in the inner query (为了避免对给定的派生表进行多次具体化,我们可以将派生表具体化一次,即在内部查询(t2.a
) and then an outer join on the lifted predicate (t1.a = derived.a
) in order to select the correct group to match up with the outer row. t2.a
)中引用的表的联接列上添加一个分组,然后在提升谓词(t1.a=derived.a
)上添加一个外部联接,以便选择与外部行匹配的正确组。(If the subquery already has an explicit grouping, the extra grouping is added to the end of the grouping list.) (如果子查询已经有显式分组,则额外的分组将添加到分组列表的末尾。)The query previously shown can thus be rewritten like this:因此,前面显示的查询可以这样重写:
SELECT t1.* FROM t1
LEFT OUTER JOIN
(SELECT a, COUNT(*) AS ct FROM t2 GROUP BY a) AS derived
ON t1.a = derived.a
AND
REJECT_IF(
(ct > 1),
"ERROR 1242 (21000): Subquery returns more than 1 row"
)
WHERE derived.a > 0;
In the rewritten query, 在重写的查询中,REJECT_IF()
represents an internal function which tests a given condition (here, the comparison ct > 1
) and raises a given error (in this case, ER_SUBQUERY_NO_1_ROW
) if the condition is true. REJECT_IF()
表示测试给定条件的内部函数(这里,比较ct>1
) 如果条件为true
,则引发给定的错误(在本例中为ER_SUBQUERY_NO_1_ROW
)。This reflects the cardinality check that the optimizer performs as part of evaluating the 这反映了在计算任何提升谓词之前,优化器作为计算JOIN
or WHERE
clause, prior to evaluating any lifted predicate, which is done only if the subquery does not return more than one row.JOIN
或WHERE
子句的一部分执行的基数检查,只有在子查询不返回多行时才执行该检查。
This type of transformation can be performed, provided the following conditions are met:只要满足以下条件,就可以执行这种类型的转换:
The subquery can be part of a 子查询可以是SELECT
list, WHERE
condition, or HAVING
condition, but cannot be part of a JOIN
condition, and cannot contain a LIMIT
or OFFSET
clause. SELECT
列表、WHERE
条件或HAVING
条件的一部分,但不能是JOIN
条件的一部分,并且不能包含LIMIT
或OFFSET
子句。In addition, the subquery cannot contain any set operations such as 此外,子查询不能包含任何集合操作,如UNION
.UNION
。
The WHERE
clause may contain one or more predicates, combined with AND
. WHERE
子句可以包含一个或多个谓词,并结合AND
。If the 如果WHERE
clause contains an OR
clause, it cannot be transformed. WHERE
子句包含OR
子句,则无法对其进行转换。At least one of the WHERE
clause predicates must be eligible for transformation, and none of them may reject transformation.WHERE
子句谓词中必须至少有一个符合转换条件,并且它们都不能拒绝转换。
To be eligible for transformation, a 要符合转换条件,WHERE
clause predicate must be an equality predicate in which each operand should be a simple column reference. WHERE
子句谓词必须是相等谓词,其中每个操作数都应是简单的列引用。No other predicates—including other comparison predicates—are eligible for transformation. 没有其他谓词(包括其他比较谓词)可以进行转换。The predicate must employ the equality operator 谓词必须使用相等运算符=
for making the comparison; the null-safe ≪=>
operator is not supported in this context.=
进行比较;在此上下文中不支持空安全运算符<=>
。
A 仅包含内部引用的WHERE
clause predicate that contains only inner references is not eligible for transformation, since it can be evaluated before the grouping. WHERE
子句谓词不适合转换,因为可以在分组之前对其求值。A 仅包含外部引用的WHERE
clause predicate that contains only outer references is eligible for transformation, even though it can be lifted up to the outer query block. WHERE
子句谓词有资格进行转换,即使它可以提升到外部查询块。This is made possible by adding a cardinality check without grouping in the derived table.这可以通过在派生表中添加基数检查而不进行分组来实现。
To be eligible, a 要符合条件,WHERE
clause predicate must have one operand that contains only inner references and one operand that contains only outer references. WHERE
子句谓词必须有一个仅包含内部引用的操作数和一个仅包含外部引用的操作数。If the predicate is not eligible due to this rule, transformation of the query is rejected.如果谓词由于此规则而不合格,则拒绝查询的转换。
A correlated column can be present only in the subquery's 相关列只能出现在子查询的WHERE
clause (and not in the SELECT
list, a JOIN
or ORDER BY
clause, a GROUP BY
list, or a HAVING
clause). WHERE
子句中(而不能出现在SELECT
列表、JOIN
或ORDER BY
子句、GROUP BY
列表或HAVING
子句中)。Nor can there be any correlated column inside a derived table in the subquery's 子查询的FROM
list.FROM
列表中的派生表中也不能有任何相关列。
A correlated column can not be contained in an aggregate function's list of arguments.聚合函数的参数列表中不能包含相关列。
A correlated column must be resolved in the query block directly containing the subquery being considered for transformation.必须在直接包含要考虑转换的子查询的查询块中解析相关列。
A correlated column cannot be present in a nested scalar subquery in the WHERE
clause.WHERE
子句中的嵌套标量子查询中不能存在相关列。
The subquery cannot contain any window functions, and must not contain any aggregate function which aggregates in a query block outer to the subquery. 子查询不能包含任何窗口函数,也不能包含在子查询外部的查询块中聚合的任何聚合函数。A COUNT()
aggregate function, if contained in the SELECT
list element of the subquery, must be at the topmost level, and cannot be part of an expression.COUNT()
聚合函数如果包含在子查询的SELECT
列表元素中,则必须位于最顶层,并且不能是表达式的一部分。
See also Section 13.2.11.8, “Derived Tables”.另请参阅第13.2.11.8节,“导出表”。