• 조인이란 결국 집합을 연결고리(조인 조건)를 통해 서로 연결하는 것이기 때문에 연결고리 상태가 조인에 커다란 영향을 미치게 된다.
  • 연결고리 상태란 주어진 조인조건의 연산자의 형태와 그들이 가지고 있는 인덱스의 상태를 말한다.

2.2.1. 연결고리 정상

  • 조인의 연결조건 양쪽 테이블에 모두 인덱스가 존재하는 경우

  • 어느 방향으로 조인을 해도 큰 문제는 없어 보인다.
  • 연결고리 정상인 경우 1:M 의 관계에 있다 하더라도 발생되는 연결작업의 논리적인 양은 동일하다.
  • 즉, 연결고리 정상 상태에서 1:M 관계나 연결방향은 수행속도를 좌우하는 큰 요소가 아니다.
  • 수행속도를 좌우하는것은 조인 조건보다는 필터조건에 따른 열결 방향이다.
  • 처리범위를 최대한 줄인 후 연결하느냐 연결한 후에 필요없는 자료를 버리느냐?


{section}

{column:width=50}

조인처리


SELECT a.fld1, ....., a.fldn
     , b.col1, ....., b.coln
  FROM tab2 b, tab1 a
 WHERE a.key1 = b.key2
   AND b.col2 LIKE 'AB%'
   AND a.fld1 = '10'
 ORDER BY a.fld2
;

{column}

{column:width=50}
{column}

{section}
개념 이해를 위해 극단적인 가정을 해보자.

  • Tab1의 Fld1 = '10' 을 만족하는 범위 5000 건
  • Tab2의 col2 LIKE 'AB%' 를 만족하는 범위 100 건
  • Tab1 : Tab2 = 2 : 1 이며 연결고리로 연결했을때 모두 연결 성공한다.

  • 외부적으론 동일한 결과를 내지만 연결방향에 따라 내부적인 처리량의 차이가 엄청난것을 알 수 잇다.
  • 조인의 양을 먼저 많이 줄여줄 수 있는 테이블을 먼저 엑세스 하면 처리량이 줄어든다.
  • RBO 모드에서는 이퀄조건을 우선하여 잘못된 엑세스 경로를 선택할 수 있다.
  • CBO 모드에서는 데이터 분포도에 따라 Tab2가 먼저 엑세스 되도록 실행계획을 수립할 것이다.
  • 하지만 실제 데이터에 따라 달라지는 것이므로 어느 방향이라 단언 할 수 없다.
  • 사용자가 어느방향의 연결이 유리한지를 정확하게 알고 있다면 ORDERED 나 LEADING 힌트로 제어해 주는 것도 좋다.

2.2.2. 한쪽 연결고리 이상


  • 연결고리 이상이 있는 테이블을 먼저 엑세스 하거나 인덱스와 무관하게 소트머지나 해시조인을 수행하도록 해야 한다.
  • 이런 이유로 RBO 에서는 한쪽에 인덱스가 없으면 무조건 없는쪽을 먼저 처리하도록 실행계획을 수립한다.
  • 이를 역이용하여 연결고리를 강제로 끊어(조인조건 가공) 원하는 실행계획을 유도하기도 한다.
조인되는 컬럼이 1:1 로 대응되지 않는 경우
  • 원래 테이블의 키는 a,b,c 이지만 다른 테이블에서는 통함된 d라는 하나의 통합된 외뢰키를 만들어 사용.
  • 애초에 설계 잘못으로 다음 두가지 유형중 하나를 선택하여 연결방향을 고정시켜야 한다.
  • 상황변화에 유연하게 대처하지 못하므로 이런식의 설계는 지양해야 한다.
    {section}
    {column:width=20}

SELECT *
  FROM tab1, tab2
 WHERE a||b||c = d
;

{column}

{column:width=20}


SELECT *
  FROM tab1, tab2
 WHERE a = SUBSTR(d, 1, 2)
   AND b = SUBSTR(d, 3, 1)
   AND c = SUBSTR(d, 4, 3)
;

{column}

{column:width=60}
{column}
{section}

데이터 타입의 차이에 의해 발생되는 경우
  • 연결고리 조인 컬럼의 데이터 타입이 서로 다른 경우
  • CHAR 와 NUMBER 연결시 CHAR 가 NUMBER 로 자동 형변환되어 한쪽 연결고리 이상 발생
  • CHAR 와 DATE 연결시 CHAR 가 DATE 로 자동 형변환되어 한쪽 연결고리 이상 발생
  • 마찬가지로 설계의 문제

2.2.3. 양쪽 연결고리 이상

  • 양쪽 모두 연결고리에 인덱스가 없다면 억지 NL조인은 엄청난 횟수의 풀테이블스캔이 발생된다.
  • 따라서 연결고리 상태에 영향을 받지 않는 소트머지나 해시조인 방식으로 실행계획을 수립하게 된다.
  • 물론 대량의 경우 이방식이 더 유리할수도 있으나 어느 한가지 방식만을 고집할수 없으므로
  • 여러 상환에 유연하게 대처가 가능하도록 연결고리 정상상태를 만들어 주는것이 좋겠다.


연결고리 이상 실전 예제 1

{section}
{column:width=50}

BETWEEN


SELECT *
  FROM tab1 x, tab2 y
 WHERE y.key1 = x.key1
   AND y.key2 BETWEEN '200501' AND '200503'
;

{column}

{column:width=50}
{column}
{section}

  • y의 인덱스가 key1 + key2 이라면 연결고리 정상
  • y의 인덱스가 key2 + key1 이라면 연결고리 이상 : 선두컬럼이 = 조건이 아닌 범위 조건임
  • Between 을 In으로 바꾸어 = 조건을 만들어 줌
    {section}
    {column:width=50}

IN


SELECT *
  FROM tab1 x, tab2 y
 WHERE y.key1 = x.key1
   AND y.key2 IN ('200501', '200502', '200503')
;

{column}

{column:width=50}
{column}
{section}

  • 범위조건이 항상 IN 으로 대체 가능한것은 아니다.
  • 이경우 In 서브쿼리를 이용할 수 있다.
    {section}
    {column:width=50}

IN 서브쿼리


SELECT *
  FROM tab1 x, tab2 y
 WHERE y.key1 = x.key1
   AND y.key2 IN (SELECT ymd
                    FROM date_dual
                   WHERE ymd BETWEEN :start_Dt AND :end_Dt
                  )
;

{column}

{column:width=50}
{column}
{section}

  • 이론적으로는 연결고리 이상을 만들지 않을 수 있을것 같다.
  • 하지만 서브쿼리가 나타나는 순간 문제는 간단하지가 않다.
  • tab2가 key2의 조건값을 상수값으로 받기 위해선 서브쿼리가 먼저 수행되어야 하는데
  • 이러한 제약은 이미 tab1과 tab2 사이의 평등관계에 영향을 미치기 때문이다.


연결고리 이상 실전 예제 2

  • Tab1 > (Tab2 , Tab3) 로 연결된다면 연결고리 정상
  • Tab2 > Tab1 > Tab3 또는 Tab3 > Tab1 > Tab2 로 연결된다면 연결고리 이상
  • (Tab2 , Tab3) > tab1 로 연결될수 있다면 연결고리 정상 가능하다.
  • Tab2 와 Tab3 의 자료가 극히 적다고 가정하고 카티젼곱을 통해 이를 구현한 것이 스타조인이다.


연결고리 이상 실전 예제 3

  • key1 은 tab1에서 상속받아 tab2, tab3 까지 이어졌다.
  • 이때 (b)와 같이 x와 y를 비교하게 된다면?
  • z.key1이 상수값으로 주어진다고 해도 x에서는 이를 사용못하며, 반드시 y를 거쳐야만 x를 읽을 수 있다.
  • z.key 에 상수 조건이 주어진다면 쿼리변환에 의해 x나 y도 바로 상수조건이 적용되지만
  • z.key 에 상수 조건이 주어진것이 아니므로 실행계획이 한쪽 방향으로만 고정된다.(z > y > x)
  • 이렇듯 조인절을 어떤 테이블끼리 비교하느냐에 따라 연결고리 이상이 발생할 수 있으며
  • 조건절의 테이블 알리아스만 살짝 변경해주는것만으로도 엄청난 성능향상 효과가 발생되기도 한다.