您的位置:首页 > 数据库 > MySQL

mysql5.7官网直译SQL语句优化--外部链接简单化

2017-11-15 14:12 344 查看
1.9 Outer Join Simplification.外部连接简单化

查询中from条件中表的表达式可以有多种方式简单化。

在分析阶段,包含右外连接操作的查询可以被转换为值包含左连接操作的查询。在一般情况下,转变回产生在如下的右连接中:(T1, ...) RIGHT JOIN (T2, ...) ON P(T1, ..., T2, ...)

变成等价的左连接:(T2, ...) LEFT JOIN (T1, ...) ON P(T1, ..., T2, ...)

所有的内部连接表达式用集合T1,T2,P(T1,T2)来取代形式为T1 INNER JOIN T2 ON P(T1,T2)

的条件,将会和where条件结合连接(或者是说如果存在的话,会和内嵌连接条件做连接)。

当优化器评价外部连接操作的执行计划时,它考虑的只有where条件,对于每一个这样的操作,外部表都会在内部表之前访问。优化器的选择会被限制,因为只有这样一个计划能够通过使用嵌套循环算法在外部连接中。比方说查询如下,其中R(T2)极大的减少了来自T2表中匹配的行数:

SELECT * T1 LEFT JOIN T2 ON P1(T1,T2)

  WHERE P(T1,T2) AND R(T2)

如果查询执行的顺序和写的是一样的,优化器只有一种选择,既在查找有限制的表T2之前查找无限制的表T1,这将会产生一个效率低下的查询执行计划。

相反,mysql转变查询为一个没有外连接操作的查询,如果where条件是null-rejected的话。(也就是说,将外连接转变为内连接)而对于一个外连接的null-rejected条件产生的条件为如果对于操作生成的任何NULL-complemented(零补齐)行的评估都是false或者是UNKNOWN。

这样,比方说这个外连接:T1 LEFT JOIN T2 ON T1.A=T2.A

类似如此的条件可以被称为null-rejected,因为对于任何NULL-complemented行都不可能是true.(其中T2列设置为null):

T2.B IS NOT NULL

T2.B > 3

T2.C <= T1.C

T2.B < 2 OR T2.C > 1

类似如此的条件则不是null-rejected,因为他有可能是true对于一个null-complemented行数据:

T2.B IS NULL

T1.B < 3 OR T2.B IS NOT NULL

T1.B < 3 OR T2.B > 3

如何来判断对于一个外连接操作来说一个条件是不是null-rejected的规则还是简单的:

>如果是A is not null,其中A是任何内部表中的一个属性。

>预示着包含一个引用对于一个内部表评估为UNKNOWN当他们的参数之一是null的话。

>一个连接词包含了一个共同的null-rejected条件。

>一个对null-rejected条件的分离。

如果一个条件可以被看做是null-rejected,在一个外连接的操作中,且没有null-rejected在其他连接中。在这个查询中,where条件对于第二个外连接操作是null-rejected,但对于第一个不是:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A

                 LEFT JOIN T3 ON T3.B=T1.B

  WHERE T3.C > 0

如果在一个查询中,where条件是一个null-rejected对于一个外连接操作,那么外连接操作可以被一个内连接操作取代。例如,在上一个例子中,第二个外连接是一个null-rejected,则可以被取代为如下:

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

第一次转变查询:

ELECT * 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是一个null-rejected。下面的查询是完全没有外连接查询的查询语句:

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条件不是null-rejected对于被嵌入的外连接,但是对于嵌入外连接的连接条件T2.A=T1.A AND T3.C=T1.C 是null-rejected:

  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

到此外连接优化的说明就结束了,接下来我们要说的是1.10 Multi-Range Read Optimization多范围读取优化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息