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 을 수행한다.
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 하는것은 경우에 따라서 신중히 고려하여 수행하여야 한다.
어차피 똑똑한 옵티마이져가 알아서 할테지만 ...
댓글 없음:
댓글 쓰기