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

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




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

데이터 모델과 정렬 작업의 관계

group by, union, distinct 같은 연산자가 불필요하게 많이 사용되는 패턴을 보이는 경우, 데이터 모델이 잘 정규화 되지 않음을 알 수 있다.
즉, 데이터 모델 이상으로 발생한 데이터 중복 제거하기 위해서 sort 명령을 수행하게 되는 경우이다.

CASE

  • 사례1.
    1. 상황 : 과금은 매달 한번씩 발생하고, 하나의 과금에 대해서 여러번에 걸쳐 입금 할 수 있으므로, 과금 테이블과 수납 테이블의 관계는 "1:M" 관계가 정상이나,
      문제는 과거 데이터 이관시 발생한 예외 케이스 때문에 M:M 관계로 모델을 함
    2. 정상 모델
    3. 비정상 모델
    4. 데이터 상태
    5. 튜닝 전
      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.순번
      ;
      
    6. 튜닝 후 : 1:M 관계로 모델을 변경함으로써 불필요한 group by 연산 제거 및 성능 향상
      SELECT A.상품ID, A.과금액, B.수납액, B.수납일시
      FROM   과금 A, 수납 B
      WHERE  A.과금연월    = :과금연월
      AND    A.고객ID      = :고객ID
      AND    B.고객ID(+)   = A.고객ID
      AND    B.상품ID(+)   = A.상품ID
      AND    B.과금연월(+) = A.과금연월
      ORDER BY A.상품ID, B.순번
      ;
      
  • 사례2 : PK외 관리할 속성이 없거나, 테이블의 개수 감소 목적으로 자식 테이블 통합 시키는 경우
    1. 상황 : 고객별 가입상품 레벨의 데이터 조회가 매우 빈번하게 발생할 때마다, 고객별상품라인을 group by한다면 성능 저하
    2. 정상 모델
    3. 비정상 모델 : "가입상품" 테이블을 없애고, "고객별상품라인" 테이블에 통합
    4. 비정상 모델에서의 쿼리
      SELECT 과금.고객ID, 과금.상품ID, 과금.과금액, 가입상품.가입일시
      FROM   과금,
             (SELECT 고객ID, 상품ID, MIN(가입일시) 가입일시
              FROM   고객별상품라인
              GROUP BY 고객ID, 상품ID) 가입상품
      WHERE  과금.고객ID(+)   = 가입상품.고객ID
      AND    과금.상품ID(+)   = 가입상품.상품ID
      AND    과금.과금연월(+) = :YYYYMM
      ;
      
    5. 정상 모델에서의 쿼리 - 성능 향상
      SELECT 과금.고객ID, 과금.상품ID, 과금.과금액, 가입상품.가입일시
      FROM   과금, 가입상품
      WHERE  과금.고객ID(+)   = 가입상품.고객ID
      AND    과금.상품ID(+)   = 가입상품.상품ID
      AND    과금.과금연월(+) = :YYYYMM
      ;
      
  • 사례3 : 이력 테이블에서 마지막 이력만 조회하거나, 대량 집합의 이력을 조회할 때 sort 많이 발생 시킴
    1. 상황
      1. 대안 모델1 : 새로운 이력이 쌓일 때마다 기존 값 갱신 (한번의 갱신으로 수백 번의 조회가 빠르다면 더 나은 선택임)
      2. 대안 모델2 : 현재 데이터만 주로 조회된다면, 데이터 중복이 있더라도 마스터 테이블을 이력 테이블과 별도로 관리
        ※ 데이터 모델은 다각적인 측면에서 평가가 이루어져야 하지, 특정 현상만을 보면 잘못된 모델이라고 판단해서는 안됨
    2. 예제 쿼리 : 이력 테이블에서 최근 데이터만 조회하는데, 이력 조회하는 모든 부분을 인라뷰로 감싸고 분석함수를 이용해 순번상 가장 큰 값을 갖는 레코드만 추출
      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  ......)
      ;
      

문서정보

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