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

지역을 나눠 두 사람이 동시에 돌린 정산 명세에서 지역 1 ~ 4가 통째로 빠지고 5 ~ 8은 두 벌이 됐다

기초PLSQL한빛유통484 / 700

상황 ​

정산팀의 「고객별 정산 명세 생성」 프로시저는 원래 매달 1일 밤에 전 지역을 한 번에 돌렸다. 이번 달부터 고객센터가 월초 오전에 명세를 빨리 달라고 해서, 조민우와 동료 한 명이 화면에서 지역 묶음을 나눠(1 ~ 4, 5 ~ 8) 동시에 돌리기로 했다. 11월 1일 09:00에 두 실행이 모두 '완료'로 끝났는데, 고객센터에서 지역 1 ~ 4 고객의 명세가 하나도 없고 지역 5 ~ 8 고객은 명세가 두 장씩 나온다는 연락이 왔다. 이튿날 다시 돌리자 이번에는 한쪽이 ORA-00054로 실패했다.

테이블과 인덱스 ​

  • T_ORD_STLM 정산: 100,000행 · 640블록 · 10월 정산 전체 · 인덱스 없음
  • M_CUS: 2,000행 · 30블록 · PK_M_CUS (CUS_ID) · RGN_ID 8개 지역. 지역 1 ~ 4 고객 1,012명(정산 50,410건), 지역 5 ~ 8 고객 988명(정산 49,590건)
  • W_STMT(작업 테이블, 이 문제용): 보통의 영구 테이블 · LOGGING · 인덱스 없음 · 명세 머리와 명세 줄 두 단계가 함께 읽는다.
  • T_STMT(명세 머리: 고객별) · T_STMT_DAY(명세 줄: 고객 × 정산일) · 둘 다 이 문제용 테이블이다.
  • 운영은 ARCHIVELOG다. 다른 배치는 이 시간에 W_STMT를 쓰지 않는다.

원본 SQL ​

sql
PROCEDURE P_STMT_BUILD(p_ym VARCHAR2, p_rgn_from VARCHAR2, p_rgn_to VARCHAR2) IS
BEGIN
  EXECUTE IMMEDIATE 'TRUNCATE TABLE W_STMT';                          -- ① 작업 테이블을 비운다

  INSERT INTO W_STMT (STLM_SEQ, CUS_ID, RGN_ID, STLM_DT, STLM_AMT)    -- ② 이번 지역 묶음의 정산
  SELECT s.STLM_SEQ, s.CUS_ID, c.RGN_ID, s.STLM_DT, s.STLM_AMT
    FROM T_ORD_STLM s, M_CUS c
   WHERE c.CUS_ID = s.CUS_ID
     AND c.RGN_ID BETWEEN p_rgn_from AND p_rgn_to;
  COMMIT;

  INSERT INTO T_STMT (STMT_YM, CUS_ID, RGN_ID, STLM_CNT, STLM_AMT)      -- ③ 명세 머리
  SELECT p_ym, CUS_ID, RGN_ID, COUNT(*), SUM(STLM_AMT)
    FROM W_STMT
   GROUP BY CUS_ID, RGN_ID;

  INSERT INTO T_STMT_DAY (STMT_YM, CUS_ID, STLM_DT, STLM_CNT, STLM_AMT) -- ④ 명세 줄
  SELECT p_ym, CUS_ID, TRUNC(STLM_DT), COUNT(*), SUM(STLM_AMT)
    FROM W_STMT
   GROUP BY CUS_ID, TRUNC(STLM_DT);
  COMMIT;
END;

실행계획 학습용 예시 ​

xplan
[11월 1일 — 두 세션의 실행 기록]
  시각         세션             단계
  09:00:02.1   A (지역 1 ~ 4)   ① TRUNCATE W_STMT
  09:00:02.6   A                ② W_STMT 50,410행 · COMMIT
  09:00:03.0   B (지역 5 ~ 8)   ① TRUNCATE W_STMT
  09:00:03.4   B                ② W_STMT 49,590행 · COMMIT
  09:00:03.9   A                ③ T_STMT 988행 · ④ T_STMT_DAY 21,874행 · COMMIT · 완료
  09:00:04.0   B                ③ T_STMT 988행 · ④ T_STMT_DAY 21,874행 · COMMIT · 완료

[T_STMT — 10월분 대조]
  지역 1 ~ 4   고객 1,012명   명세 머리      0행
  지역 5 ~ 8   고객   988명   명세 머리  1,976행 (고객마다 두 행)

[11월 2일 — 다시 돌렸을 때]
  09:10:01.2   A   ① TRUNCATE · ② INSERT 시작
  09:10:01.5   B   ① TRUNCATE W_STMT
                   ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired

[세션 통계 — 실행 한 번 (참고)]
  redo size   약 5.1 MB (그중 W_STMT 적재 약 4.6 MB)

문제 ​

  1. 지역 1 ~ 4의 명세가 0행이고 지역 5 ~ 8이 두 벌이 된 이유와, 11월 2일 ORA-00054가 난 이유를 실행 기록으로 설명하시오.
  2. 두 사람이 동시에 돌려도 서로 섞이지 않도록 고치시오. 고친 방법에서 작업 테이블의 행이 언제 사라지는지와, 같은 달을 다시 돌려도 명세가 두 벌이 되지 않게 하는 방법도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자