Skip to content
튜닝 연습DML과 배치 튜닝
DML-005

에러 로그는 깨끗한데 보정이 170건 모자란다

실전PLSQL한빛유통430 / 700

상황 ​

주간 정산 보정 배치는 월요일 11:00 정산 확정 전에 끝나야 하는데, 지난주에는 10:52에 끝났다. 정산팀 조민우: "보정 건수가 정산 건수보다 적었어요. 에러 로그는 깨끗하대요." 소스에는 주석이 둘 있다. 한 건 때문에 전체를 세우지 않는다 (2019.06 강도현)와 트랜잭션은 짧게 (5월 포스트모템 재발방지)다. 보정률 규칙(등급 A 0.1%, B 0.2%, 그 밖 0.3%)은 정산팀 규정이고 이 배치 안에만 있다.

테이블과 인덱스 ​

  • T_ORD_STLM(원장): 이번 주 정산 100,020행(P1 적재 10만 + 금액 미확정 등록 20, STLM_AMT NULL) · 약 640블록. STLM_SEQ는 겹치지 않는다.
  • M_CUS: 1,997행 · PK_M_CUS (CUS_ID). 탈퇴 고객 3명은 개인정보 파기로 마스터에서 지웠고, 그 3명의 정산이 150건이다.
  • T_STLM_ADJ(보정 이력): PK (STLM_SEQ) · ADJ_RATE · ADJ_AMT NOT NULL · ADJ_DT. 같은 주를 다시 돌리면 UPDATE 쪽으로 간다.
  • 반송함 테이블은 아직 없다. 만들어도 된다.

원본 SQL ​

sql
PROCEDURE ADJ_WEEKLY IS
  v_gd   M_CUS.CUS_GD%TYPE;
  v_rate NUMBER;
  v_cnt  NUMBER;
  n      PLS_INTEGER := 0;
BEGIN
  FOR r IN (SELECT STLM_SEQ, CUS_ID, STLM_AMT FROM T_ORD_STLM) LOOP
    BEGIN
      SELECT CUS_GD INTO v_gd FROM M_CUS WHERE CUS_ID = r.CUS_ID;                    -- 고객 등급
      v_rate := CASE v_gd WHEN 'A' THEN 0.001 WHEN 'B' THEN 0.002 ELSE 0.003 END;     -- 보정률 (정산팀 규정)
      SELECT COUNT(*) INTO v_cnt FROM T_STLM_ADJ WHERE STLM_SEQ = r.STLM_SEQ;         -- 이미 보정했나
      IF v_cnt = 0 THEN
        INSERT INTO T_STLM_ADJ (STLM_SEQ, ADJ_RATE, ADJ_AMT, ADJ_DT)
        VALUES (r.STLM_SEQ, v_rate, ROUND(r.STLM_AMT * v_rate), SYSDATE);
      ELSE
        UPDATE T_STLM_ADJ
           SET ADJ_RATE = v_rate, ADJ_AMT = ROUND(r.STLM_AMT * v_rate), ADJ_DT = SYSDATE
         WHERE STLM_SEQ = r.STLM_SEQ;
      END IF;
    EXCEPTION
      WHEN OTHERS THEN NULL;                         -- 한 건 때문에 전체를 세우지 않는다 (2019.06 강도현)
    END;
    n := n + 1;
    IF MOD(n, 1000) = 0 THEN COMMIT; END IF;         -- 트랜잭션은 짧게 (5월 포스트모템 재발방지)
  END LOOP;
  COMMIT;
END;

실행계획 실측 · 교재 15화(복사본, 보정률 함수를 루프 안 SELECT로 풀어 적은 판) ​

xplan
[세션 통계 — ADJ_WEEKLY 한 번 (보정 이력이 빈 첫 판 · 연습 DB 복사본)]
  경과 시간                  2.19 ~ 2.24 초
  CPU used by this session   1.34 ~ 1.42 초
  recursive calls            301,187
  execute count              299,769
  session logical reads      816,425
  redo size                  55.77 MB
  undo change vector size    16.71 MB
  user commits               100

[TKPROF 모양 — 루프 안의 세 문장]
  SELECT CUS_GD FROM M_CUS WHERE CUS_ID = :B1                     Execute 100,020   Fetch 100,020   (한 건 조회 · cr=3)
  SELECT COUNT(*) FROM T_STLM_ADJ WHERE STLM_SEQ = :B1             Execute  99,870   Fetch  99,870
  INSERT INTO T_STLM_ADJ (…) VALUES (:B4, :B3, ROUND(:B2*:B3), SYSDATE)   Execute  99,870   rows 99,850

[끝난 뒤 — 정합성]
  원장 T_ORD_STLM            100,020
  보정 이력 T_STLM_ADJ        99,850
  반송 · 오류 기록                 0
  원장에만 있는 정산             170   (탈퇴 고객 150 · 금액 미확정 20)

문제 ​

  1. 이 배치의 일량이 어디서 나오는지, 그리고 170건이 어디로 사라졌는지 위 통계로 설명하시오.
  2. 같은 보정을 한 문장 중심으로 다시 작성하시오. 보정할 수 없는 정산은 사유와 함께 남기고, "보정 + 반송 = 원장"이 성립하는지 배치가 스스로 확인하게 하시오.
  3. 커밋은 언제 하는지, 중간에 실패하면 어떻게 되는지, 다시 돌려도 안전한지 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자