레이블이 outer join인 게시물을 표시합니다. 모든 게시물 표시
레이블이 outer join인 게시물을 표시합니다. 모든 게시물 표시

2010년 3월 9일 화요일

쿼리변환시 OUTER JOIN

1. 스키마 생성

create table t1(c1 number,c2 number);
create table t2(c1 number,c2 number);

 

insert into t1 values(1,1);
insert into t1 values(2,1);
insert into t1 values(3,1);
insert into t1 values(4,1);
insert into t1 values(5,1);


insert into t2 values(1,1);
insert into t2 values(2,2);
insert into t2 values(3,2);

 

SQL> select * from t1;

 C1    C2
---------- ----------
  1     1
  2     1
  3     1
  4     1
  5     1

 

SQL> select * from t2;

 C1    C2
---------- ----------
  1     1
  2     2
  3     2

 

 

옵티마이져는 기본적으로 Push Selection 을 선호한다. ( 조인연산 및 Cost 가 발생하는 집합연산을 하기전에 미리 Selection 연산을 수행하면 결과집합의 수를 줄일수 있기때문. )

 

OUTER JOIN 도 이러한 기법을 사용할수 있다.

하지만 자연조인 방식대로 사용한다면 쿼리 변환시 결과 집합이 달라질수 있는 오류를 범할수 있다.

예를 들어보자.

 

위의 스키마를 이용하여 LEFT OUTER JOIN 을 수행한다.

select * from T1 LEFT OUTER JOIN T2 ON T1.c1 = T2.c1;

 

 

 C1    C2       C1  C2
---------- ----------

  1     1          1   1
  2     1          2   2
  3     1          3   2
  5     1
  4     1

 

 T1.C1 = T2.C1 의 조건으로 수행하였기 때문에 오른쪽 릴레이션에 일치하는 값이 없더라도 NULL 로 결과집합에 포함되며. 왼쪽 릴레이션 또한 나머지 튜플들을 결과집합에 포함시키는걸 확인할 수 있다.

 

그럼 여기서 T2 테이블 ( RIGHT ) 에 조건을 추가해보자

select * from T1 LEFT OUTER JOIN T2 ON T1.c1 = T2.c1 where T2.c1 = 2;

 

 

 C1    C2       C1  C2
---------- ----------

  2     1           2   2

 

T1 과 T2 가 JOIN 후에 Where 조건절에 대한 Selection 이 일어난 것을 볼수 있다.

 

만일 T1, T2 가 매우 큰 릴레이션이고, Where 조건절이 매우 낮은 Selectivity 를 가지는 경우라면,

Join 하기전에 미리 Selection 연산을 수행하는것이 효율적이라고 생각할수 있을것이다.

 

Push Selection 기법을 사용하여 쿼리를 변환해보자.

1. select * from T1 LEFT OUTER JOIN T2 ON t1.c1 = t2.c1 AND T2.c1 = 2;

2. select * from T1 LEFT OUTER JOIN (select * from T2 where c1 = 2) T2 ON T1.c1 = T2.c1;

 

Where 조건절을 Join 조건절로 Push 하였다.

T2 릴레이션이 조건절에 대한 Selection 수행하여 릴레이션의 크기를 줄이고 T1 과 Join 하는것으로 보인다.

 

그럼 결과도 같을까?

SQL> select * from T1 LEFT OUTER JOIN T2 ON t1.c1 = T2.c1 AND T2.c1 = 2;

 C1    C2       C1  C2
---------- ----------
  2     1          2   2
  5     1
  4     1
  3     1
  1     1

 

SQL> select * from T1 LEFT OUTER JOIN (select * from T2 where c1 = 2) T2 ON T1.c1 = T2.c1;

 

 C1    C2       C1  C2
---------- ----------

  2     1          2   2
  5     1
  4     1
  3     1
  1     1

 

아.. 결과가 바뀌었다. 결과가 바뀔수 있는 쿼리변환은 의미가 없다.

왜 결과가 바뀌었을까? 이유는 간단하다.

 

OUTER JOIN 의 특성을 고려하지 않고 Push Selection 연산을 수행하였기 때문이다.

OUTER JOIN ON 절에 조건절을 추가하면 해당 조건절에 대해서 조인하기전에 이미 필터링이 일어난 집합을 가지고 JOIN 을 수행하게된다.

 

하지만 Where 절에 조건절을 추가하게되면 JOIN 이 완료된 집합에 대해서 조건절을 체크하게 되는데,

이경우 OUTER JOIN 의 특성을 잃어 버리게된다.

 

Push Selection 을 보장받고 싶다면 다음과 같이 변환한다.

SQL> select * from T1 LEFT OUTER JOIN T2 ON T1.c1 = T2.c1 AND T2.c1 = 2 where T2.c1 = 2;

 

 C1    C2       C1  C2
---------- ----------

  2     1           2   2

Push Selection 연산시 where 절의 조건을 삭제하지 않고 남겨 두어야 동일한 결과를 나타낼 수 있다.  

 

따라서 OUTER JOIN 에 대해서 Push Selection 하는것은 경우에 따라서 신중히 고려하여 수행하여야 한다.

어차피 똑똑한 옵티마이져가 알아서 할테지만 ...