오라클 성능 고도화 원리와 해법 II (2016년)
고급 조인 테크닉 0 0 4,601

by 구루비 분석함수 선이력 선분이력 테이블복제 [2017.04.12]


08. 고급 조인 테크닉

1) 누적 매출 구하기

분석함수를 이용한 누적매출


select 지점, 판매월, 매출, sum(매출) over (partition by 지점 order by 판매월
                                           range between unbounded preceding and current row) 누적매출
  from 월별지점매출

- 분석함수는 오라클 8i부터 제공

2) 선분이력 끊기

월도를 기준으로 변환한 선분이력


select b. 상품번호, greatest(a . 시작일자, b . 시작일자) 시작일자
     , least(a . 종료일자, b . 종료일자) 종료일자, b. 데이터
  from 월도 a, 선분이력 b
 where b.시작일자 <= a.종료일자
   and b.종료일자 >= a.시작일자

- 겹치는 구간의 시작일자는 두 시작일자 중 큰값, 종료일자는 두 종료일자 중 작은값

3) 데이터 복제를 통한 소계 구하기

복제용 테이블을 활용한 소계


1. 복제기법을 활용한 소계 및 총계
column 부서번호 format a10
select decode(no, 3, null, to char(deptno)) 부서번호
     , decode(no, 1, to char(empno) , 2, '부서계' , 3, '총계' ) 사원번호
     , sum(sa1) 급여합, round (avg (sal) ) 급여평균
  from emp a, (select rownum no from dual connect by level <= 3)
  group by decode(no, 3, null, to char(deptno))
         , no, decode (no, 1, to char (empno) , 2, '부서계', 3, '총계' )
  order by 1, 2;

2. 표준 rollup 구문을 활용한 소계 및 총계
break on 부서 번호
column 부서번호 format 9999
column 사원번호 format a10
select deptno 부서 번호
     , case when grouping(empno) = 1 and grouping(deptno) 1 then '총계'
       when grouping(empno) = 1 then '부서계'
       else to char(empno) end 사원번호
, sum(sal) 급여합, round(avg(sal)) 급여평균
  from emp
 group by rollup(deptno, empno)
 order by 1, 2;

4) 상호배타적 관계의 조인

  • 어떤 엔티티가 두개 이상의 다른 엔티티의 합칩합과 관계를 갖는것을 '상호배타적 관계'(Exclusive OR)라고 한다.
    아래 그림에서 상품권 결제 테이블과 온라인권 및 실권 테이블과의 관계가 상호배타적 관계에 해당

서로 다른 상품권 결제 테이블의 설계 방식에 따른 쿼리작성


1. 온라인권번호, 실권번호 두 컬럼을 따로 두고, 레코드별로 둘 중 하나의 컬럼에만 값을 입력
select /*+ ordered use nl(b) use nl(c) use nl(d) */
       a.주문번호, a.결제일자, a.결제금액
     , nvl(b.온라인권번호, c.실권번호) 상품권번호
     , nvl(b.발행일시, d.발행일시) 발행일시  
  from 상품권결제 a, 온라인권 b, 실권 c, 실권발행 d
 where a. 결제일자 between :dtl and :dt2
   and b. 온라인권번호(+) = a. 온라인권번호
   and c. 실권번호(+) = a. 실권번호
   and d. 발행번호(+) = c. 발행번호

2. 상품권구분과, 상품권번호컬럼 구분. 구분: 1 - 온라인권번호, 2 - 실권번호
select /*t ordered use nl(b) use nl(c) use nl(d) */
       a.주문번호, a.결제일자, a .결제금액
     , nvl(b.온라인권번호, c.실권번호) 상품권번호
     , nvl(b.발행일시, d.발행일시) 발행일시
  from 상품권결제 a, 온라인권 b, 실권 c, 실권발행 d
 where a.결제일자 between :dt1 and :dt2
 and b.온라인권번호 (+) = decode(a.상품권구분, '1', a.상품권번호)
 and c.실권번호 (+) = decode(a.상품권구분 '2' , a. 상품권번호)
 and d.발행번호 (+) = c.발행번호

5) 최종 출력 건에 대해서만 조인하기

게시판 등의 화면 페이지 처리


1. 인덱스 구성
게시판_X01 : 게시판유형 + 등록일자 DESC + 번호 + 질문유형

2. 쿼리 구성
SELECT /*+ ORDERED USE NL(A) USE_NL(B) USE_NL(C) USE_NL(D) ROWID(A) * /
        A.등록일자, B.변호, A.제목, B.회원명 , C.게시판유형명, D.질문유형명, X.CNT
  FROM (
        SELECT RID, ROWNUM ID, COUNT (*) OVER () CNT
          FROM (
                SELECT ROWID RID
                  FROM 게시판
                 WHERE 게시판유형 = :TYPE
                 ORDER BY 등록일자 DESC, 질문유형, 번호
         WHERE ROWNUM <= 31
        ) X, 게시판 A, 회원 B, 게시판유형 C, 질문유형 D
  WHERE X.ID BETWEEN 21 AND 30
    AND A.ROWID = X.RID
    AND B.회원번호 = A.작성자번호
    AND C.게시판유형 = A.게시판유형
    AND D.질문유형 = A.질문유형


- 인덱스에 질문유형을 추가하여 모든 테이블을 조인하여 모든 데이터를 출력한 후 SORT를 실행하는것이 아닌
  인덱스 블록만 읽어 SORT까지 우선 처리하고 조인한다.


6) 징검다리 테이블 조인을 이용한 튜닝

  • FROM 절에서 조인되는 테이블 개수를 늘려 성능을 향상

  • 성능 저하의 원인은 테이블 조인 시 발생하는 부하
  • 서비스요금할인_N1 : 서비스상품그룹 + 할인기간코드 + 서비스코드
  • 위와 같이 인덱스에 서비스코드를 추가 하고 서비스와 서비스요금할인 테이블을 한번 더 조인수행 시 조인 시 발생하는 부하를 줄일 수 있다.
  • 인덱스에서 얻어진 집합끼리 조인할 때는 대량 데이터 조인이므로 해쉬 조인방식을 사용
  • 인덱스에 없는 컬럼 값을 읽는 경우 추가적인 인덱스 탐색 없이 인덱스에서 읽은 rowid값을 가지고 엑세스
  • 서비스와 서비스요금할인 테이블을 두 번씩 엑세스하도록 쿼리를 작성했지만 실제 거리 일량은 아래처럼 한번 엑세스한 것과 같다.
인조 식별자 사용에 의한 조인 성능 이슈
  • 엑세스 경로에 대한 고려 없이 인조식별자(Artificial Identifier)를 설계하는 경우 위에서 나온 조인 성능 이슈가 자주 발생

인조식별자의 장단점


- 장점
 1. 인조식별자를 두면 PK, FK가 단일 컬럼으로 구성되므로 테이블 간 연결 구조가 단순해져서 이들 제약조건을 위해 사용되는 인덱스 저장공간이 최소화
 2. 다중 컬럼으로 조인할 때보다 조인연산을 위한 CPU 사용량이 상대적으로 조금 줄 수 있다. (미미한 정도)

- 단점 
 1. 조인 연산 횟수와 블록 I/O 증가로 더 많은 시스템 리소스를 낭비하기 쉽다.
 2. 엑세스 범위를 줄이지 못하면서 단지 조인을 위해서만 사용되는 PK인덱스가 많이 양산될 수 있다
 3. 데이터 모델을 이해하기 어려워진다. (실질 식별자를 찾기 어려워 엔티티의 가독성이 떨어짐)

=> 업무적으로 이미 통용되는 식별자이거나 유연성/확장성을 고려해 인조식별자를 설계하는 경우를 제외하면 
   가급적 인조식별자를 주지 않는 것이 좋다. 물리설계 단계에서 저장효율과 엑세스 효율 등을 고려하여 결정하는 것이 낫다.

7) 점이력 조회

  • 점이력 : 데이터 변경이 발생할 때마다 변경일자와 함께 새로운 이력 레코드를 쌓는 방식. 흔히 서브쿼리를 사용한다.

8) 선분이력 조인

9) 선분이력 조인 튜닝

10) 조인에 실패한 레코드 읽기

"구루비 주주클럽 스터디모임" 에서 2016년에 "오라클 성능 고도화 원리와 해법 II " 도서를 스터디하면서 정리한 내용 입니다.

- 강좌 URL : http://www.gurubee.net/lecture/3346

- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^

- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입