Skip to content
튜닝 연습옵티마이저와 통계
OPT-012

ROLLBACK했다는 일 마감 배치의 숫자가 본사 대시보드에 그대로 떠 있다

기초PLSQL버거602 / 700

상황 ​

버거 본사의 「일 매출 마감」 배치는 매일 02:10에 전날 주문을 매장별로 세어 SHOP_DAY_SUM에 넣는다. 매장 POS가 마감 때 보낸 주문 수(SHOP_CLOSE)와 한 곳이라도 다르면 전부 되돌리고, POS가 다시 보내면 재실행한다. 지난달 조민우가 "적재 직후 통계 수집" 원칙을 따라 INSERT 바로 뒤에 통계 수집을 넣었다. 8월 6일 새벽 로그에는 마감 불일치 1곳 → ROLLBACK이 남았는데, 아침 대시보드에는 SH0137의 어제 주문이 3건으로 떠 있었다(POS 보고는 9건).

테이블과 인덱스 ​

  • SHOP_DAY_SUM 매장 일 매출(이 문제용): SHOP_NO · SUM_DT · ORD_CNT · 하루 200행
  • SHOP_CLOSE 매장 마감 보고(이 문제용): SHOP_NO · CLOSE_DT · ORD_CNT · POS가 마감 때 보낸다
  • ORD: 1,000,000행 · 22,422블록 · ORD_DT VARCHAR2(8) · 하루 약 1,370건(매장당 약 7건) · ORD_X01 (ORD_DT, ORD_HMS)
  • PKG_LOG.WRITE는 자율 트랜잭션으로 로그만 남긴다. 배치 본문은 자율 트랜잭션이 아니다.

원본 SQL ​

sql
PROCEDURE P_DAY_CLOSE(p_dt VARCHAR2) IS          -- p_dt = '20130805'
  v_diff NUMBER;
BEGIN
  DELETE FROM SHOP_DAY_SUM WHERE SUM_DT = p_dt;

  INSERT INTO SHOP_DAY_SUM (SHOP_NO, SUM_DT, ORD_CNT)
  SELECT SHOP_NO, p_dt, COUNT(*)
    FROM ORD
   WHERE ORD_DT = p_dt
   GROUP BY SHOP_NO;

  -- 2013-07 조민우 : 적재 직후 통계 수집
  DBMS_STATS.GATHER_TABLE_STATS(USER, 'SHOP_DAY_SUM');

  SELECT COUNT(*) INTO v_diff
    FROM SHOP_DAY_SUM s, SHOP_CLOSE c
   WHERE s.SUM_DT = p_dt AND c.CLOSE_DT = p_dt
     AND c.SHOP_NO = s.SHOP_NO
     AND c.ORD_CNT <> s.ORD_CNT;

  IF v_diff > 0 THEN
    ROLLBACK;
    PKG_LOG.WRITE('P_DAY_CLOSE', '마감 불일치 ' || v_diff || '곳 → ROLLBACK · 재실행 대기');
    RETURN;
  END IF;

  COMMIT;
END;

실행계획 학습용 예시 ​

xplan
[배치 로그 — 8월 6일 새벽]
 02:10:01  P_DAY_CLOSE('20130805') 시작
 02:10:02  DELETE 0 · INSERT 200
 02:10:02  GATHER_TABLE_STATS SHOP_DAY_SUM 완료 (0.4초)
 02:10:03  마감 불일치 1곳 → ROLLBACK · 재실행 대기
 09:20:00  SH0137 POS 재전송 도착 (재실행 전)

[08:30 — SHOP_DAY_SUM 의 20130805 행]
 COUNT(*) 200 · SH0137 ORD_CNT 3 (SHOP_CLOSE.ORD_CNT 9)
 SCN_TO_TIMESTAMP(ORA_ROWSCN) = 02:10:02      ← 이 행들을 확정한 커밋의 시각

문제 ​

  1. ROLLBACK을 했는데도 200행이 남은 이유를 로그의 시각으로 설명하시오.
  2. "적재 직후 수집"의 뜻을 살리면서 배치를 고치시오. 통계 수집을 자율 트랜잭션 프로시저로 빼는 안이 왜 틀린지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자