Skip to content
튜닝 연습파티션
PART-042

본사 월별 판매 추이 리포트의 8월 건수가 매장 마감 합계보다 702건 많다

중급DDL유통417 / 700

상황 ​

유통 본사 리포트 DB는 2023년 7월분부터 판매 사본 CF10_P의 월 적재를 파티션 교환으로 바꿨다. 매월 2일 01:00에 운영 CF10에서 지난달 판매를 스테이징 테이블로 떠서, 미리 만들어 둔 빈 칸과 맞바꾼다. 교환은 매번 0.1초 안에 끝난다. 9월 4일 회계팀이 본사 「월별 판매 추이」의 8월 건수가 매장 마감 보고 합계보다 702건 많다고 알려 왔다. 그런데 매장 포털의 「8월 매출」과 「일 매출」 화면은 매장 마감과 맞는다.

테이블과 인덱스 ​

  • CF10_P 판매 사본(리포트 DB, 문제 설정): CF10과 같은 컬럼(SLE_NO · SLE_DT · SLE_HMS · SLE_DOW · SHP_NO)을 PARTITION BY RANGE (SLE_DT) 월별 24칸(P202201 ~ P202312, 경계는 VALUES LESS THAN ('20220201') 꼴)과 빈 PMAX로 나눴다. P202307은 19번째, P202308은 20번째 칸이다. 9월 4일 현재 데이터가 있는 칸은 P202201 ~ P202308 20칸이고, 칸 하나는 약 20,800행, FULL로 약 191블록이다.
  • CF10 운영 판매: SLE_DT는 VARCHAR2(8)이다. 매장 마감 보고는 7월 20,686건, 8월 21,104건이고, 8월 1일은 702건, 9월 1일은 688건이다.
  • PK CF10_P_PK (SLE_NO, SLE_DT): LOCAL 유니크 인덱스. GLOBAL 인덱스는 없다.
  • 교환 뒤 스테이징 테이블에는 원래 칸의 내용(비어 있던 칸)이 남으므로 바로 지운다.

원본 SQL ​

sql
-- 매월 2일 01:00 · 지난달 판매를 교환으로 넣는다 (9월 2일 : :v_from = '20230801', :v_to = '20230901')
CREATE TABLE CF10_STG AS
SELECT SLE_NO, SLE_DT, SLE_HMS, SLE_DOW, SHP_NO
  FROM CF10
 WHERE SLE_DT BETWEEN :v_from AND :v_to;

ALTER TABLE CF10_STG ADD CONSTRAINT CF10_STG_PK PRIMARY KEY (SLE_NO, SLE_DT);

ALTER TABLE CF10_P
  EXCHANGE PARTITION P202308 WITH TABLE CF10_STG
  INCLUDING INDEXES WITHOUT VALIDATION;

DROP TABLE CF10_STG PURGE;

-- 본사 「월별 판매 추이」
SELECT SUBSTR(SLE_DT, 1, 6) AS ym, COUNT(*) AS cnt
  FROM CF10_P
 GROUP BY SUBSTR(SLE_DT, 1, 6)
 ORDER BY ym;

실행계획 학습용 예시 ​

xplan
[본사 「월별 판매 추이」 · 9월 4일]
---------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name   | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |        |      1 |        |     21 | 00:00:00.09 |    3851 |        |       |
|   1 |  SORT GROUP BY               |        |      1 |     20 |     21 | 00:00:00.09 |    3851 |        |       |
|   2 |   PARTITION RANGE ALL        |        |      1 |   417K |   418K | 00:00:00.06 |    3851 |      1 |    25 |
|   3 |    TABLE ACCESS FULL         | CF10_P |     20 |   417K |   418K | 00:00:00.05 |    3851 |      1 |    25 |
---------------------------------------------------------------------------------------------------------------------
  결과 일부 :  202307  20,686   ·   202308  21,806   ·   202309  688

[매장 포털 「8월 매출」 · :v_from = '20230801', :v_to = '20230831']
---------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name   | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |        |      1 |        |      1 | 00:00:00.01 |     193 |        |       |
|   1 |  SORT AGGREGATE              |        |      1 |      1 |      1 | 00:00:00.01 |     193 |        |       |
|*  2 |   FILTER                     |        |      1 |        |  21104 | 00:00:00.01 |     193 |        |       |
|   3 |    PARTITION RANGE ITERATOR  |        |      1 |  21104 |  21104 | 00:00:00.01 |     193 |    KEY |   KEY |
|*  4 |     TABLE ACCESS FULL        | CF10_P |      1 |  21104 |  21104 | 00:00:00.01 |     193 |    KEY |   KEY |
---------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(:V_FROM<=:V_TO)
   4 - filter(("SLE_DT">=:V_FROM AND "SLE_DT"<=:V_TO))

  (실행 때 고른 칸: 20번 P202308 하나 · 「일 매출」 SLE_DT = '20230801' 도 이 칸만 읽고 702건)

[매장 마감 보고]  7월 20,686  ·  8월 21,104  ·  9월은 아직 마감 전

문제 ​

  1. 칸을 고르는 화면은 맞는데 전체 칸을 읽는 리포트만 702건 많은 까닭을 적재 SQL과 실행계획으로 설명하시오. 9월 행 688건이 벌써 보이는 까닭도 쓰시오.
  2. 지금 잘못 들어간 행을 찾아 바로잡는 SQL과, 같은 일이 다시 생기지 않는 적재 SQL을 작성하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자