by-nc-sa     개발자, DBA가 함께 만들어가는 구루비 지식창고!

3. 데이터 모델 측면에서의 검토




  • 불합리한 데이터 모델이 소트 오퍼레이션을 유발하는 경우가 많은데, GROUP BY, UNION, DISTINCT 같은 연산자가 많을 경우
    데이터 모델이 잘 정규화되지 않았거나, 데이터 모델 이상으로 발생한 데이터 중복을 제거하려는 과정에서 소트를 유발함

1. 사례1

  • 아래의 테이블 관계는 1:M 관계인 과금과 수납 테이블인데, 컨버전 시 발생한 예외 Case 때문에 M:M 관계가 되어
    항상 GROUP BY를 하게 되고 이로 인해 성능이 나빠지는 내용이다.

1) 1:M 정상 관계 ERD

2) M:M 비 정상 관계 ERD

3) M:M 관계를 극복하기 위한 SQL

SELECT A.상품ID,
       A.과금액,
       B.수납액,
       B.수납일시
FROM   (SELECT 고객ID,
               상품ID,
               과금연월,
               SUM(과금액) 과금액
        FROM   과금
        WHERE  과금연월 = :과금연월
        AND    고객ID   = :고객ID
        GROUP BY 고객ID,
                 상품ID,
                 과금연월) A,
       수납 B
WHERE  A.고객ID   = B.고객ID(+)
AND    A.상품ID   = B.상품ID(+)
AND    A.과금연월 = B.과금연월(+)
ORDER BY A.상품ID,
         B.순번
;

4) M:M 관계 상세 ERD

5) 1:M 관계로 변경 후(컨버전) SQL

SELECT A.상품ID,
       A.과금액,
       B.수납액,
       B.수납일시
FROM   과금 A,
       수납 B
WHERE  A.고객ID   = B.고객ID(+)
AND    A.상품ID   = B.상품ID(+)
AND    A.과금연월 = B.과금연월(+)
AND    A.과금연월 = :과금연월
AND    A.고객ID   = :고객ID
ORDER BY A.상품ID,
         B.순번
;

2. 사례2

  • PK외에 관리할 속성이 없거나, '가입상품'처럼 소수일 때, 테이블 개수를 줄이기 위해 자식 테이블과 통합하는 경우 발생되는 소트 부하 예제
  • 데이터 누락 및 정합성에도 문제가 없지만, 만약 고객별 가입상품 레벨의 데이터를 조회가 빈번할 경우 '고객별상품라인' 테이블이 이미 하위
    레벨(상태코드)로 내려왔기 때문에 가입일시만을 가져오기 위해서는 반드시 GROUP BY를 사용해야 하므로 성능에 안좋음
  • 그러므로 반 정규화를 할 때 반드시 어플리케이션 레벨까지 고려를 해야 함.

1) 정규화가 잘 된 ERD

2) 반 정규화 된 ERD

3) 반 정규화 된 SQL

SELECT 과금.고객ID,
       과금.상품ID,
       과금.과금액,
       가입상품.가입일시
FROM   과금,
       (SELECT 고객ID,
               상품ID,
               MIN(가입일시) 가입일시
        FROM   고객별상품라인
        GROUP BY 고객ID,
                 상품ID) 가입상품
WHERE  가입상품.고객ID  = 과금.고객ID(+)     
AND    가입상품.상품ID  = 과금.상품ID(+)     
AND    과금.과금연월(+) = :YYYYMM
;

4) 정규화 된 SQL

SELECT 과금.고객ID,
       과금.상품ID,
       과금.과금액,
       가입상품.가입일시
FROM   과금,
       가입상품
WHERE  가입상품.고객ID  = 과금.고객ID(+)     
AND    가입상품.상품ID  = 과금.상품ID(+)     
AND    과금.과금연월(+) = :YYYYMM
;     

3. 사례_3

  • 순번(Sequence) 컬럼을 증가시키면서 순서대로 데이터를 적재하는 점이력 모델은 선분이력에 비해 DML 부하는 최소화되지만,
    이력조회 시 많는 소트를 발생시킴
  • 아래 예제는 순번으로 관리될 때 분석함수를 사용하여 마지막 이력만 조회하는 업무를 구현한 내용인데, SQL만 보고도 많은
    소트가 발생될 거라는 것을 짐작해 볼 수 있다.
SELECT ......
FROM   (SELECT ......
        FROM   소송심급피해대상 A,
               소송대상청구     B,
               소송심급         C,
               소송             D,
               소송결재         E,
               민원마스터       F,
               VOC유형코드      G,
               (SELECT ......
                FROM   (SELECT ......,
                               RANK() OVER(PARTITION BY ...... ORDER BY 종결년도 DESC, 종결순번 DESC) RANK
                        FROM   소송심급대상종결 A)
                WHERE   RANK = 1) H,
               (SELECT ......
                FROM   (SELECT ......,
                               RANK() OVER(PARTITION BY ...... ORDER BY 마감일자 DESC) RANK
                        FROM   피해청구 A)
                WHERE   RANK = 1) I,
               (SELECT ......
                FROM   (SELECT ......,
                               RANK() OVER(PARTITION BY ...... ORDER BY A.판결년도 DESC, A.순번 DESC) RANK
                        FROM   판결         A,
                               소송피해내용 B,
                               소송금       C,
                               소승소득내용 D,
                               (SELECT ......
                                FROM   (SELECT ......,
                                               RANK() OVER(PARTITION BY ...... ORDER BY 순번 DESC) RANK
                                        FROM   소송결재
                                        WHERE  ......)
                                WHERE  RANK = 1) E
                        WHERE  A.판결년도 = B.판결년도
                        AND    A.판결순번 = B.판결순번
                        AND    ......)
                WHERE   RANK = 1) J,
               (SELECT ......
                FROM   (SELECT ......,
                               RANK() OVER(PARTITION BY ...... ORDER BY A.특인차수 DESC, B.순번 DESC) RANK
                        FROM   특인     A,
                               특인결재 B
                        WHERE  A.특인년도 = B.특인년도
                        AND    A.특인순번 = B.특인순번
                        AND    ......)
                WHERE   RANK = 1) K,
               (SELECT ......
                FROM   (SELECT ......,
                               RANK() OVER(PARTITION BY ...... ORDER BY A.소송심급피해대상순번 DESC) RANK
                        FROM   소송대상청구     A,
                               소송심급피해대상 B,
                               소송심급         C,
                               소송             D
                        WHERE  ......)
                WHERE   RANK = 1) L
        WHERE  ......)
;
  • 이를 해결하기 위한 대안으로는 FLAG 컬럼을 추가하여 마지막 이력에 대한 레코드를 관리할 경우 소트 부하를 없앨 수 있다.

문서에 대하여

문서정보

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.