Table expressions in the 在许多情况下,查询的FROM
clause of a query are simplified in many cases.FROM
子句中的表表达式会简化。
At the parser stage, queries with right outer join operations are converted to equivalent queries containing only left join operations. 在解析器阶段,具有右外部联接操作的查询将转换为仅包含左联接操作的等效查询。In the general case, the conversion is performed such that this right join:在一般情况下,执行转换以使此右连接:
(T1, ...) RIGHT JOIN (T2, ...) ON P(T1, ..., T2, ...)
Becomes this equivalent left join:成为此等效的左连接:
(T2, ...) LEFT JOIN (T1, ...) ON P(T1, ..., T2, ...)
All inner join expressions of the form T1 INNER JOIN T2 ON P(T1,T2)
are replaced by the list T1,T2
, P(T1,T2)
being joined as a conjunct to the WHERE
condition (or to the join condition of the embedding join, if there is any).T1 INNER JOIN T2 ON P(T1,T2)
形式的所有内部联接表达式都被列表T1,T2
、P(T1,T2)
替换为与WHERE
条件(或嵌入联接的联接条件,如果有的话)的联接。
When the optimizer evaluates plans for outer join operations, it takes into consideration only plans where, for each such operation, the outer tables are accessed before the inner tables. 当优化器评估外部联接操作的计划时,它只考虑计划,其中对于每个这样的操作,外部表在内部表之前被访问。The optimizer choices are limited because only such plans enable outer joins to be executed using the nested-loop algorithm.优化器的选择是有限的,因为只有这样的计划才能使用嵌套循环算法执行外部联接。
Consider a query of this form, where 考虑此表单的查询,其中R(T2)
greatly narrows the number of matching rows from table T2
:R(T2)
极大地缩小表T2
中匹配行的数目:
SELECT * T1 LEFT JOIN T2 ON P1(T1,T2) WHERE P(T1,T2) AND R(T2)
If the query is executed as written, the optimizer has no choice but to access the less-restricted table 如果查询是按编写的方式执行的,那么优化器别无选择,只能先访问限制较少的表T1
before the more-restricted table T2
, which may produce a very inefficient execution plan.T1
,然后再访问限制较多的表T2
,这可能会产生非常低效的执行计划。
Instead, MySQL converts the query to a query with no outer join operation if the 相反,如果WHERE
condition is null-rejected. WHERE
条件为null
,MySQL会将查询转换为没有外部联接操作的查询。(That is, it converts the outer join to an inner join.) (即,它将外部联接转换为内部联接。)A condition is said to be null-rejected for an outer join operation if it evaluates to 如果为外部联接操作生成的任何空补码行的计算结果为FALSE
or UNKNOWN
for any NULL
-complemented row generated for the operation.FALSE
或UNKNOWN
,则该条件被称为NULL
拒绝。
Thus, for this outer join:因此,对于此外部联接:
T1 LEFT JOIN T2 ON T1.A=T2.A
Conditions such as these are null-rejected because they cannot be true for any 此类条件被拒绝为NULL
-complemented row (with T2
columns set to NULL
):null
,因为它们对于任何NULL
补充行(T2
列设置为null
)都不能为true
:
T2.B IS NOT NULL T2.B > 3 T2.C <= T1.C T2.B < 2 OR T2.C > 1
Conditions such as these are not null-rejected because they might be true for a 此类条件不会被NULL
-complemented row:NULL
拒绝,因为它们对于NULL
补足行可能为true
:
T2.B IS NULL T1.B < 3 OR T2.B IS NOT NULL T1.B < 3 OR T2.B > 3
The general rules for checking whether a condition is null-rejected for an outer join operation are simple:检查外部联接操作的条件是否为null
拒绝的一般规则很简单:
It is of the form 它的形式是A IS NOT NULL
, where A
is an attribute of any of the inner tablesA IS NOT NULL
,其中A
是任何内部表的属性
It is a predicate containing a reference to an inner table that evaluates to 它是一个谓词,包含对内部表的引用,当其参数之一为UNKNOWN
when one of its arguments is NULL
NULL
时,该表的计算结果为UNKNOWN
It is a conjunction containing a null-rejected condition as a conjunct它是一个包含null
拒绝条件的连词,作为连词
It is a disjunction of null-rejected conditions它是null
拒绝条件的析取
A condition can be null-rejected for one outer join operation in a query and not null-rejected for another. 查询中的一个外部联接操作可以为null
拒绝条件,而另一个外部联接操作不能为null
拒绝条件。In this query, the 在此查询中,WHERE
condition is null-rejected for the second outer join operation but is not null-rejected for the first one:WHERE
条件对于第二个外部联接操作为null
拒绝,但对于第一个外部联接操作为not null
拒绝:
SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A LEFT JOIN T3 ON T3.B=T1.B WHERE T3.C > 0
If the 如果查询中的外部联接操作拒绝WHERE
condition is null-rejected for an outer join operation in a query, the outer join operation is replaced by an inner join operation.WHERE
条件为null
,则外部联接操作将替换为内部联接操作。
For example, in the preceding query, the second outer join is null-rejected and can be replaced by an inner join:例如,在前面的查询中,第二个外部联接被null
拒绝,可以由内部联接替换:
SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A INNER JOIN T3 ON T3.B=T1.B WHERE T3.C > 0
For the original query, the optimizer evaluates only plans compatible with the single table-access order 对于原始查询,优化器只评估与单表访问顺序T1,T2,T3
. T1,T2,T3
兼容的计划。For the rewritten query, it additionally considers the access order 对于重写的查询,它还考虑访问顺序T3,T1,T2
.T3,T1,T2
。
A conversion of one outer join operation may trigger a conversion of another. 一个外部联接操作的转换可能会触发另一个外部联接操作的转换。Thus, the query:因此,查询:
SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A LEFT JOIN T3 ON T3.B=T2.B WHERE T3.C > 0
Is first converted to the query:首先转换为查询:
SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A INNER JOIN T3 ON T3.B=T2.B WHERE T3.C > 0
Which is equivalent to the query:这相当于查询:
SELECT * FROM (T1 LEFT JOIN T2 ON T2.A=T1.A), T3 WHERE T3.C > 0 AND T3.B=T2.B
The remaining outer join operation can also be replaced by an inner join because the condition 其余的外部联接操作也可以由内部联接替换,因为条件T3.B=T2.B
is null-rejected. T3.B=T2.B
被null
拒绝。This results in a query with no outer joins at all:这将导致查询完全没有外部联接:
SELECT * FROM (T1 INNER JOIN T2 ON T2.A=T1.A), T3 WHERE T3.C > 0 AND T3.B=T2.B
Sometimes the optimizer succeeds in replacing an embedded outer join operation, but cannot convert the embedding outer join. 有时,优化器成功地替换了嵌入的外部联接操作,但无法转换嵌入的外部联接。The following query:以下查询:
SELECT * FROM T1 LEFT JOIN (T2 LEFT JOIN T3 ON T3.B=T2.B) ON T2.A=T1.A WHERE T3.C > 0
Is converted to:转换为:
SELECT * FROM T1 LEFT JOIN (T2 INNER JOIN T3 ON T3.B=T2.B) ON T2.A=T1.A WHERE T3.C > 0
That can be rewritten only to the form still containing the embedding outer join operation:只能重写为仍包含嵌入外部联接操作的表单:
SELECT * FROM T1 LEFT JOIN (T2,T3) ON (T2.A=T1.A AND T3.B=T2.B) WHERE T3.C > 0
Any attempt to convert an embedded outer join operation in a query must take into account the join condition for the embedding outer join together with the 任何转换查询中嵌入的外部联接操作的尝试都必须考虑嵌入外部联接的联接条件以及WHERE
condition. WHERE
条件。In this query, the 在此查询中,嵌入外部联接的WHERE
condition is not null-rejected for the embedded outer join, but the join condition of the embedding outer join T2.A=T1.A AND T3.C=T1.C
is null-rejected:WHERE
条件不是null
拒绝,但是嵌入外部联接T2.A=T1.A AND T3.C=T1.C
的联接条件是null
拒绝:
SELECT * FROM T1 LEFT JOIN (T2 LEFT JOIN T3 ON T3.B=T2.B) ON T2.A=T1.A AND T3.C=T1.C WHERE T3.D > 0 OR T1.D > 0
Consequently, the query can be converted to:因此,查询可以转换为:
SELECT * FROM T1 LEFT JOIN (T2, T3) ON T2.A=T1.A AND T3.C=T1.C AND T3.B=T2.B WHERE T3.D > 0 OR T1.D > 0