3.2.2.4. 세미조인(Semi Join)

  • 비교연산자에 의해 사용된 서브쿼리도 넓은 의미로는 조인이나 마찬가지다.
  • 단, 조인은 조인되는 집합간에 어느집합이 먼저 수행되느냐가 상관없지만, 서브쿼리는 메인쿼리에 종속관계이므로, 조인형태를 취하더라도, 메인집합에 변형을 가해서는 안된다.
  • M*1은 M이므로, 서브쿼리는 항상 '1'집합 모양이 되어야, 변형이 안되는것이다.
    => '1'집합이라는게 증명되면, 옵티마이저는 조인과 동일한 실행계획을 수립한다.
  • 서브쿼리가 'M'집합이면, 옵티마이저는 메인집합에 변형을 가하지 않게 하기 위해 중간처리를 한다.
  • 서브쿼리가 먼저 수행된다면, 'SORT(UNIQUE)'처리를 하여 메인쿼리에 '1'집합과 조인하게 해주고,
    서브쿼리가 나중에 수행된다면, 메인쿼리가 바깥쪽의 Loop가 되어서, 안쪽 Loop인 서브쿼리와 첫번째 연결에 성공하면 바로 안쪽 Loop를 빠져나오는 방식으로 처리하는 것이다.
{code:SQL}
/* Nested Loops Semi Join */
SELECT *
FROM emp
WHERE deptno
IN (SELECT deptno
FROM t_emp
WHERE sal > 2000
);
{code}
{code:SQL}






















--
IdOperationNameRowsBytesCost (%CPU)Time























--

0SELECT STATEMENT1461645 (0)00:00:01
1NESTED LOOPS SEMI1461645 (0)00:00:01
2TABLE ACCESS FULLEMP145183 (0)00:00:01
  • 3
TABLE ACCESS BY INDEX ROWIDT_EMP997K6817K3 (0)00:00:01
  • 4
INDEX RANGE SCANT_EMP_IDX12 (0)00:00:01























--

 |
| {code:SQL}
/* Filter처리 */
SELECT *
FROM   emp
WHERE  deptno
IN     (SELECT /*+ NO_UNNEST */ deptno
	FROM   t_emp
        WHERE  sal > 2000
       );

|


----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     5 |   185 |     9   (0)| 00:00:01 |
|*  1 |  FILTER            |       |       |       |            |          |
|   2 |   TABLE ACCESS FULL| EMP   |    14 |   518 |     3   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| T_EMP |     2 |    14 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------

|

  • Sort Merge나 해쉬조인으로 유도하기 위해서, 10g부터는 서브쿼리에 일반적인 조인과 같이 'USE_MERGE'나 'USE_HASH'힌트를 사용하면된다.
{code:SQL}
/* Hash Join Right Semi */
SELECT *
FROM t_emp
WHERE deptno
IN (SELECT deptno
FROM emp
WHERE sal > 2000
);
{code}
{code:SQL}























IdOperationNameRowsBytesCost (%CPU)Time
























0SELECT STATEMENT1396K65M2161 (6)00:00:26
  • 1
HASH JOIN RIGHT SEMI1396K65M2161 (6)00:00:26
2TABLE ACCESS BY INDEX ROWIDEMP10702 (0)00:00:01
  • 3
INDEX RANGE SCANEMP_SAL_IDX101 (0)00:00:01
4TABLE ACCESS FULLT_EMP1396K55M2133 (5)00:00:26
























 |

h3. 3.2.2.5. 카티젼 조인(Cartesian Join)

- 카티젼조인은 조인되는 두 개의 집합간에 연결고리가 되는 조건이 전혀 없는 경우를 말한다. 넓은 의미에서 보면 M:M 조인을 말하기도 한다.

- 실제로는 실행계획에서 'CARTESIAN'으로 나오는 조인은 Sort Merge조인뿐이며, 다른조인은 정상적인 조인과 동일하게 실행계획이 나타난다.

- 카티젼 조인이 발생하는 경우는 특별한 목적으로 고의적으로 만드는 경우와, 3개 이상의 집합을 조인할 때 조인순서의 잘못으로 연결고리가 빠져서 발생하는 경우가 있다.

h3. 3.2.2.6. 아우터 조인(Outer Join)

- 아우터 조인은 어떤 대상집합을 기준으로 거기에 아우터 조인되어 있는 집합에 대응되는 Row가 없더라도 기준집합의 모든 Row를 리턴하는 조인이다,

*{+}Nested Loops 아우터 조인{+}*
- 이 조인은 반드시 기준이 되는 집합이 바깥쪽 루프로써 먼저 수행되어야 하기때문에, 목적없이 함부로 아우터 조인을 시키면 조인의 방향이 고정되므로 주의한다.

- 이 방식으로 유도하는 힌트는 기존 'USE_NL(table1, table2)'을 사용하며 실행계획은 동일하나 'NESTED LOOPS(OUTER)'로 표현되는 것이 다르다.

*{+}Hash 아우터 조인{+}*
- Nested Loops조인으로는 부담이 되는 대량의 데이터이거나 인덱스 등의 문제로 NL조인으로 수행에 문제가 있을때 선택될 수있다.

- 이 방식에서도 기준집합은 무조건 빌드입력(Build Input)을 담당하고, 내측 조인집합이 해쉬테이블로 생성되어 연결작업이 수행된다.

- 해쉬조인에서는 역할이 고정되드라도 NL조인에서와 같은 부담은 크게 발생하지 않는다.(2.3.4 해쉬조인참고)

- 조인뷰나 조인 인라인뷰와 아우터 조인을 수행하면  뷰의 병합이나 조건절 진입이 허용되지 않고, 뷰의 전체집합이 독립적으로 수행된 결과와 아우터 조인을 수행한다.
  => 경우에 따라서는, 뷰내로 조건들이 파고 들어갈 수 없으므로 심각한 부하를 발생시킬 수 있다.

- 내측테이블의 특정조건을 만족하는 집합과 아우터 조인을 시도해야 한다면, 조건을 담은 집합을 인라인뷰로 만든 후 아우터 조인을 하면 해당 조건을 만족 할수 있다.

- 인라인뷰가 단일테이블로 구성된 경우에는 조건절 진입(Pushing Predicates)가 가능하므로, 처리범위를 줄일 수 있다.

- 조인된 인라인 뷰는 조건절 진입이 불가능하게 되므로, 인라인뷰 내에서 충분히 처리범위를 줄일 수 없다면, 아우터 조인으로 인해 심각한 수행속도 저하를 가져올수 있다.

*{+}Sort Merge 아우터 조인{+}*
- Nested Loops조인으로는 부담이 되는 대량의 데이터이거나 인덱스 등의 문제로 NL조인으로 수행에 문제가 있을때 선택될 수있다.

- 또한, 조건 연산자로 인해 해쉬조인이 불가능 할때이거나, 이미 다른 처리에 의해 조인을 위한 정렬이 선행되어 있어서 더 유리해질때 적용된다.

*{+}전체 아우터 조인{+}*
- 양쪽 집합이 모두 기준집합이면서 대응집합이 되는 아우터 조인이다.

- 먼저 한 쪽을 기준으로 아우터조인을 수행한 결과와 다른 쪽을 기준으로 부정형 조인을 한 결과를 결합해서 리턴하는 방법이다.

- 이러한 경우는 설계상의 문제나, 데이터의 일관성에 대한 문제가 원인이 되는 경우가 많다.

- 이러한 경우 다양한 대안들이 있으며, 예를 들어 UNION ALL로 합집합을 만들고 GROUP BY를 이용하여 최소공배수 집합을 만드는 방법 또는 인라인뷰, 사용자 지정 저장형 함수 등을 활용하는 방법이 있다.

h3. 3.2.2.7. 인덱스 조인

* SELECT절에 나열한 모든컬럼이 하나 이상의 인덱스에 존재하여, 테이블을 엑세스하지 않고 인덱스들로만 처리하는 방법

* 여러 개의 인덱스중에 가장 효율적인 것만 이용하고, 나머지는 테이블을 엑세스하여 체크하는 것이 일반적으로 유리하나, 뚜렷하게 효율적인 인덱스가 없다면, 인덱스를 병합하여 범위를 줄이는 것도 하나의 방법이다.

* 인덱스를 경유하여 다른 인덱스를 액세스하는 것은 불가능. 그러므로 인덱스 병합은 ROWID로 액세스 하는 Nested Loops형식으로는 불가능 하며, 머지나 해쉬 조인으로만 가능하다.

- 인덱스를 조인한다고 해서 항상 유리한 것은 아니므로, 함부로 유도하지 말하야 한다.

- 자주 같이 액세스되며, 특정 컬럼 때문에 테이블을 액세스해야 하는 경우가 많이 발생한다면 인덱스 조인을 활용할수있다.