[Oracle] 오라클 고급 JOIN 테크닉 - 상호배타적 관계의 JOIN

 상호배타적 관계의 JOIN

- 상호배타적 관계 : 어떤 엔티티가 두 개 이상의 다른 엔티티의 합집합과 관계를 갖는 것

- 상품권결제 테이블 모델링 방법

① 온라인권번호, 실권번호 두 컬럼을 따로 두고, 레코드별로 둘 중 하나의 컬럼에만 값을 입력 

    외래키 분리

SELECT /*+ ordered use_nl(b) use_no(c) use_nl(d) */

           A.주문번호, A.결제일자, A.결제금액,

NVL(B.온라인권번호, C.실권번호) 상품권번호,

NVL(B.발행일시, D.발행일시) 발행일시

  FROM 상품권결제 A

LEFT OUTER JOIN 온라인권 B

ON B.온라인권번호 = A.온라인권번호

LEFT OUTER JOIN 실권 C

ON C.실권번호 = A.실권번호

LEFT OUTER JOIN 실권발행 D

ON D.발행번호 = C.발행번호

WHERE A.결제일자 BETWEEN :dt1 AND :dt2;

② 상품권구분과 상품권번호 컬럼을 두고, 상품권구분이 '1'일 때는 온라인권번호를 입력, '2'일 때는 실권번호를 입력

    → 외래키 통합

SELECT X.주문번호, X.결제일자, X.결제금액, Y.온라인권번호 상품권번호, Y.발행일시

  FROM 상품권결제 X, 온라인권 Y

WHERE X.상품권구분 = '1'

    AND X.결제일자 BETWEEN :dt1 AND :dt2

    AND X.상품권번호 = Y.온라인권번호

UNION ALL

SELECT X.주문번호, X.결제일자, X.결제금액, Y.실권번호 상품권번호, Z.발행일시

  FROM 상품권결제 X, 실권 Y, 실권발행 Z

WHERE X.상품권구분 = '2'

    AND X.결제일자 BETWEEN :dt1 AND :dt2

    AND X.상품권번호 = Y.실권번호

    AND Y.발행번호 = Z.발행번호;

-- 인덱스가 【상품권구분 + 결제일자】 순이라면 비효율 없음

-- 인덱스가 【결제일자 + 상품권구분】 순이라면 인덱스 스캔범위 중복 발생

-- 인덱스가 【결제일자 라면 상품권구분을 필터링하기 위한 테이블 random access까지 발생

SELECT /*+ ordered use_nl(b) use_nl(c) use_no(d) */

      A.주문번호, A.결제일자, A.결제금액,

      NVL(B.온라인권번호, C.실권번호) 상품권번호,

      NVL(B.발행일시, D.발행일시) 발행일시

  FROM 상품권결제 A

LEFT OUTER JOIN 온라인권 B

ON B.온라인권번호 = DECODE(A.상품권구분,'1',A.상품권번호)

LEFT OUTER JOIN 실권 C

ON C.실권번호 = DECODE(A.상품권구분,'2',A.실권번호)

LEFT OUTER JOIN 실권발행 D

ON D.발행번호 = C.발행번호

WHERE A.결제일자 BETWEEN :dt1 AND :dt2;

-- DECODE를 없애도 결과는 같지만 JOIN 량이 두 배가 됨


by 정미나 2017.11.11 12:59