【MySQL系列--优化2】——外连接简化

来源:互联网 发布:程序员之死的文化深意 编辑:程序博客网 时间:2024/06/05 15:45

许多情况下简化了查询的FROM子句中的table 表达式。 在解析器阶段,具有右外连接操作的查询将转换为仅包含左连接操作的等效查询。在一般情况下,执行转换,使得该权限加入:

(T1, ...) RIGHT JOIN (T2, ...) ON P(T1, ..., T2, ...)

变成相等的左外连接:

(T2, ...) LEFT JOIN (T1, ...) ON P(T1, ..., T2, ...)

所有内部连接表达式形式为T1 INNER JOIN T2 ON P(T1,T2)被替换为列表T1,T2,P(T1,T2)作为结合到WHERE条件(或连接到嵌入join,如果有的话)。

当优化器评估外部联接操作的计划时,仅考虑在每个此类操作之前,在内部表之前访问外部表的计划。优化器的选择是有限的,因为只有这样的计划才能使用嵌套循环算法来执行外连接。

考虑这种形式的查询,其中R(T2)大大缩小了表T2中匹配行的数量:

SELECT * T1 LEFT JOIN T2 ON P1(T1,T2)  WHERE P(T1,T2) AND R(T2)

如果以书面形式执行查询,则优化程序别无选择,只能在更受限制的表T2之前访问较不受限制的表T1,这可能会产生非常低效的执行计划。
相反,如果WHERE条件为空拒绝,MySQL将查询转换为无外部连接操作的查询。 (即,它将外部连接转换为内部连接。)对于外部连接操作,如果为操作生成的任何NULL补码行计算为FALSE或UNKNOWN,则说明条件被拒绝。
从而,对于这个外连接:

T1 LEFT JOIN T2 ON T1.A=T2.A

这些条件因为对于任何NULL互补行(T2列设置为NULL)不能为true而被空拒绝:

T2.B IS NOT NULLT2.B > 3T2.C <= T1.CT2.B < 2 OR T2.C > 1

这些条件不会被空拒绝,因为它们对于NULL补码行可能是真的:

T2.B IS NULLT1.B < 3 OR T2.B IS NOT NULLT1.B < 3 OR T2.B > 3

用于检查条件是否为外部联接操作被拒绝的一般规则很简单:

  1. 它的形式为A IS NOT NULL,其中A是任何内部表的属性
  2. 它是一个包含对内部表的引用的谓词,当其中一个参数为NULL时
  3. 它将评估为UNKNOWN
  4. 它是一个包含无效拒绝条件作为结合的连接 这是无效拒绝条件的分离

对于查询中的一个外部连接操作,条件可以被空拒绝,而对另一个外部联接操作不能被空拒绝。在此查询中,WHERE条件对于第二个外部连接操作是空拒绝的,但不是第一个外部连接操作的空拒绝:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 LEFT JOIN T3 ON T3.B=T1.B  WHERE T3.C > 0

如果查询中的外部连接操作的WHERE条件为空拒绝,则外部连接操作将被内部连接操作替换。 例如,在前面的查询中,第二个外部连接被空拒绝,可以由内部连接替换:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 INNER JOIN T3 ON T3.B=T1.B  WHERE T3.C > 0

对于原始查询,优化程序仅评估与单个表访问顺序T1,T2,T3兼容的计划。对于重写的查询,它另外考虑访问顺序T3,T1,T2。 一个外部连接操作的转换可以触发另一个外部连接操作的转换。因此,查询:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 LEFT JOIN T3 ON T3.B=T2.B  WHERE T3.C > 0

首先转换为查询:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 INNER JOIN T3 ON T3.B=T2.B  WHERE T3.C > 0

这相当于查询:

SELECT * FROM (T1 LEFT JOIN T2 ON T2.A=T1.A), T3  WHERE T3.C > 0 AND T3.B=T2.B

由于条件T3.B = T2.B被空拒绝,剩余的外连接操作也可以由内连接替换。这导致一个没有外部连接的查询:

SELECT * FROM (T1 INNER JOIN T2 ON T2.A=T1.A), T3  WHERE T3.C > 0 AND T3.B=T2.B

有时,优化程序成功替换嵌入式外连接操作,但无法转换嵌入式外连接。以下查询:

SELECT * FROM T1 LEFT JOIN              (T2 LEFT JOIN T3 ON T3.B=T2.B)              ON T2.A=T1.A  WHERE T3.C > 0

转换为:

SELECT * FROM T1 LEFT JOIN              (T2 INNER JOIN T3 ON T3.B=T2.B)              ON T2.A=T1.A  WHERE T3.C > 0

这可以重写为仍然包含嵌入外连接操作的形式:

SELECT * FROM T1 LEFT JOIN              (T2,T3)              ON (T2.A=T1.A AND T3.B=T2.B)  WHERE T3.C > 0

任何在查询中转换嵌入式外连接操作的尝试都必须考虑嵌入外连接和WHERE条件的连接条件。在此查询中,WHERE条件对于嵌入式外连接不会被空拒绝,但嵌入外连接T2.A = T1.A和T3.C = T1.C的连接条件为空拒绝:

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

因此,查询可以转换为:

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
原创粉丝点击