Join pedicate Pushing

  • Join Predicate Pushing은 Join 조건이 View 내부로 Pushing 되는 현상을 의미
  • no_push_pred 힌트를 사용하여 Join Predicate Pushing을 막은 경우
  • t3.c1 = v.c1(+) 조건으로 인해 View 안으로 Pushing 되지 못하므로 인라인 뷰와 Main Query가 별개로 최적화 됨

select /*+ gather_plan_statistics no_push_pred(v) */
  t3.c1, v.c2
from
  t3, 
  (select t1.c1 as c1, t2.c2 as c2, t1.c3 as c3
    from t1, t2
    where t1.c1 = t2.c1
    order by t1.c1, t2.c2) v
where
  t3.c1 = v.c1(+) and
  t3.c3 = 1
; 
  
Execution Plan
--------------------------------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=18 Card=1 Bytes=51)
   1    0   HASH JOIN (OUTER) (Cost=18 Card=1 Bytes=51)
   2    1     TABLE ACCESS (FULL) OF 'T3' (TABLE) (Cost=2 Card=1 Bytes=26)
   3    1     VIEW (Cost=15 Card=1000 Bytes=24K)
   4    3       SORT (ORDER BY) (Cost=15 Card=1000 Bytes=50K)
   5    4         HASH JOIN (Cost=14 Card=1000 Bytes=50K)
   6    5           TABLE ACCESS (FULL) OF 'T2' (TABLE) (Cost=3 Card=1000 Bytes=24K)
   7    5           TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=10 Card=10K Bytes=254K)

1 - ACCESS PREDICATES "T3"."C1"="V"."C1"(+)
3 - FILTER PREDICATES "T3"."C3"=1

5 - ACCESS PREDICATES "T1"."C1"="T2"."C1"

  • t3.c1 = v.c1(+) 조건이 인라인 뷰안으로 Pushing 가능하다면

select /*+ gather_plan_statistics  */
  t3.c1, v.c2
from
  t3, 
  (select t1.c1 as c1, t2.c2 as c2, t1.c3 as c3
    from t1, t2
    where t1.c1 = t2.c1
    order by t1.c1, t2.c2) v
where
  t3.c1 = v.c1(+) and
  t3.c3 = 1
; 

Execution Plan
--------------------------------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=14 Card=10 Bytes=550)
   1    0   NESTED LOOPS (OUTER) (Cost=14 Card=10 Bytes=550)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'T3' (TABLE) (Cost=9 Card=1 Bytes=39)
   3    2       INDEX (RANGE SCAN) OF 'T3_N2' (INDEX) (Cost=1 Card=1)
   4    1     VIEW PUSHED PREDICATE (Cost=5 Card=1 Bytes=16)
   5    4       SORT (ORDER BY) (Cost=5 Card=1 Bytes=64)
   6    5         NESTED LOOPS (Cost=4 Card=1 Bytes=64)
   7    6           TABLE ACCESS (BY INDEX ROWID) OF 'T2' (TABLE) (Cost=2 Card=1 Bytes=25)
   8    7             INDEX (RANGE SCAN) OF 'T2_N1' (INDEX) (Cost=1 Card=1)
   9    6           INDEX (RANGE SCAN) OF 'T1_N1' (INDEX) (Cost=1 Card=1)

8 - ACCESS PREDICATES "T2"."C1"="T3"."C1"
9 - ACCESS PREDICATES "T1"."C1"="T3"."C1" FILTER PREDICATES "T1"."C1"="T2"."C1"

1 - ACCESS PREDICATES "T3"."C3"=1

  • t3.c3 = 1 조건에 의해 filtering 된 로우에 대해서만 Inline View내부에서 T2와 T3가 조인됨
  • 8번과 9번 단계의 Predicate으로 Pushing된 것을 확인 할 수 있음
  • 4번 단계에서 VIEW PUSHED PREDICATE 으로도 확인 가능함
  • HASH JOIN (OUTER)가 NESTED LOOPS (OUTER)로 바뀌면서 만족하는 데이터만 view안으로 Pushing
  • Union all을 view안에 사용하면 View Merging은 실패하지만 Join Predicate Pushing으로 인해 효율적으로 Index Range Scan과
    NL Join을 사용할 수 있음
  • 이 과정에서 Union All Partition 이라는 새로운 이름의 새로운 Operation이 등장함(Oracle 10g에서 추가되었음)