好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

MySql Outer Join 简单化

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


   所有inner join表达式形如(t1 inner join t2 on p(t1,t2))可以被(t1,t2,p(t1,t2))代替(通过where condition 做两表的conjunct或者嵌套连接条件 );

   当优化器评估带有outer join操作的join 查询执行计划时,它只考虑这几种情况,外表在内表之前被访问;

   e.g.

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

    where condition中的R(t2)减少了很多t2表中的匹配的行数,如果我们执行这条查询,优化器会毫不犹豫的先访问t1表,然后这将导致非常无效率的执行计划;

    幸运的,如果where condition 为 null-rejected,Mysql 会把像这样的查询转变为非outer join操作。对于一个outer join操作,对于任何null被填充的行,如果null-rejected的condition判断为false或者unknown( 即e.g. 对于left join,非left table,用Null值来填充行数据,当该条件可以判定该操作不成立 );

    e.g.

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

 为null-rejected的条件有:

T2.B  IS   NOT   NULL  ,
T2.B   >   3  ,
T2.C   <=   T1.C,
T2.B   <   2   OR  T2.C  >   1 

为非null-rejected的条件:

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

 对Outer join操作的null-rejected条件常规条件比较简单:

   1: 如果它是A is not null形式,当A 是任何内部表的一个属性 ;

   2: 如果一个连接包含一个null-rejected条件作为连接条件 ;

   3: 如果他是一个分裂的Null-rejected条件 ;

在一个outer join操作查询中, 一个Null-rejected条件,可能对于别的表为not 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条件对于第二个outer join操作是一个null-rejected条件,但是对于第一个就不是了。

 如果where条件对于一个outer join操作是一个 null-rejected条件,那么该outer join操作可以转化为一个inner join操作 ;

 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

一个outer join操作的转变可能触发另外一个的转变:

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

first:

 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

现在剩余的outer join操作可以被替换成一个inner join,因为条件t3.b= t2.b是一个null-rejected,所以我们得到一个没有outer join的查询

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

有时我们可以替换一个嵌套的outer join操作,但不是不能转变嵌套outer join;

 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 ,

可以被重写成依旧包含嵌套outer join操作:

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

当尝试转变一个嵌套outer join操作是,必须把嵌套的outer join的join condition和where 条件一起考虑:

 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 

where条件不是嵌套outer join的一个null-rejected条件,但嵌套outer join的连接条件 T2.A=T1.A AND T3.C=T1.C  是一个null-rejected条件,所以等效与:

 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 

 

MySql Outer Join 简单化

标签:

查看更多关于MySql Outer Join 简单化的详细内容...

  阅读:34次