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

마지막 단계에서 죽은 일 마감 체인을 절차서대로 처음부터 다시 돌리자 정산 전표가 매장마다 세 장이 됐다

실전PLSQL버거492 / 700

상황 ​

버거원 본사의 일 마감 체인은 매일 04:00에 전날분을 처리한다. 단계는 다섯이고 단계마다 커밋한다. 12월 27일 04:00 실행은 마지막 S5(POS 마스터 동기화)에서 POS 중계 서버 시간 초과로 실패했다. 당직자는 운영 절차서의 "실패하면 체인을 처음부터 다시 돌린다"에 따라 06:30에 다시 돌렸고, 이번에는 모두 성공했다. 09:10 가맹관리팀: "12월 26일 수수료 전표가 매장마다 세 장씩 있어요. 오늘 오후에 가맹점에 청구서가 나갑니다." 박팀장은 체인을 '어디서 죽어도 다시 돌릴 수 있게' 설계를 고치라고 했다. 개발팀에서는 체인 전체를 한 트랜잭션으로 묶자는 의견도 나왔다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_X01 (ORD_DT, ORD_HMS) · ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_X01 (ORD_DT, ORD_HMS) · 2013년 12월 26일 주문 1,371건, 주문상품 3,431행(판매 수량 4,803개), 매장 200곳
  • SHOP_DAY 매장 일 집계 · SHOP_MON 매장 월 누계(ORD_YM, SHOP_NO마다 한 행) · HQ_IF_DAY 본사 전송 테이블: 모두 이 문제용이며 SHOP_DAY에는 키 제약이 없다.
  • SHOP_SETTLE 가맹 수수료 전표(이 문제용): SETTLE_NO(시퀀스 SQ_SETTLE, PK) · SHOP_NO · BAS_DT · FEE_AMT(주문 1건당 120원) · CONF_YN(청구 확정 여부). 매장과 기준일로는 유일성이 걸려 있지 않다.
  • PKG_POS_IF.SYNC_MASTER: POS 중계 서버로 메뉴와 가격 마스터를 보내는 외부 연동(보통 6분 40초). 보낸 것은 DB 롤백으로 되돌릴 수 없지만, 같은 마스터를 다시 보내도 결과는 같다.
  • 체인의 단계별 실행 기록 테이블은 아직 없다. 만들어도 된다.

원본 SQL ​

sql
PROCEDURE P_DAY_CLOSE(p_d VARCHAR2) IS                 -- p_d = '20131226'
BEGIN
  -- S1 매장 일 집계
  INSERT INTO SHOP_DAY (ORD_DT, SHOP_NO, ORD_CNT, SALE_QTY)
  SELECT o.ORD_DT, o.SHOP_NO, COUNT(DISTINCT o.ORD_NO), SUM(i.ORD_ITEM_QTY)
    FROM ORD o, ORD_ITEM i
   WHERE o.ORD_DT = p_d AND i.ORD_DT = p_d AND i.ORD_NO = o.ORD_NO
   GROUP BY o.ORD_DT, o.SHOP_NO;
  COMMIT;

  -- S2 매장 월 누계에 더한다
  UPDATE SHOP_MON m
     SET m.ORD_CNT  = m.ORD_CNT  + NVL((SELECT SUM(d.ORD_CNT)  FROM SHOP_DAY d
                                        WHERE d.ORD_DT = p_d AND d.SHOP_NO = m.SHOP_NO), 0),
         m.SALE_QTY = m.SALE_QTY + NVL((SELECT SUM(d.SALE_QTY) FROM SHOP_DAY d
                                        WHERE d.ORD_DT = p_d AND d.SHOP_NO = m.SHOP_NO), 0)
   WHERE m.ORD_YM = SUBSTR(p_d, 1, 6);
  COMMIT;

  -- S3 가맹 수수료 전표
  INSERT INTO SHOP_SETTLE (SETTLE_NO, SHOP_NO, BAS_DT, FEE_AMT, CONF_YN)
  SELECT SQ_SETTLE.NEXTVAL, SHOP_NO, ORD_DT, ORD_CNT * 120, 'N'
    FROM SHOP_DAY
   WHERE ORD_DT = p_d;
  COMMIT;

  -- S4 본사 전송 테이블
  EXECUTE IMMEDIATE 'TRUNCATE TABLE HQ_IF_DAY';
  INSERT /*+ APPEND */ INTO HQ_IF_DAY (BAS_DT, SHOP_NO, ORD_CNT, SALE_QTY)
  SELECT ORD_DT, SHOP_NO, SUM(ORD_CNT), SUM(SALE_QTY)
    FROM SHOP_DAY
   WHERE ORD_DT = p_d
   GROUP BY ORD_DT, SHOP_NO;
  COMMIT;

  -- S5 POS 마스터 동기화 (외부)
  PKG_POS_IF.SYNC_MASTER(p_d);
END;

실행계획 학습용 예시 ​

xplan
[일 마감 체인 기록 — 기준일 12/26]
  실행   단계   시작       끝         처리 행   결과
  1회    S1     04:00:01   04:00:01      200    COMMIT
         S2     04:00:01   04:00:01      200    COMMIT
         S3     04:00:01   04:00:02      200    COMMIT (전표 851,201 ~ 851,400)
         S4     04:00:02   04:00:02      200    COMMIT
         S5     04:00:02   04:06:42        —    FAILED · ORA-12170 (POS 중계 서버 시간 초과)
  2회    S1 ~ S5 처음부터 (06:30:00 ~ 06:36:41) · 모두 성공 · S3 400행 (전표 851,401 ~ 851,800)

[09:20 확인 — 12/26분]
  SHOP_DAY      400행 (매장마다 같은 행 두 개)
  SHOP_MON      12월 누계에 12/26분이 세 번 들어감 (판매 수량 4,803 × 3)
  SHOP_SETTLE   600장 (매장마다 세 장) · 그중 CONF_YN = 'Y' 0장
  HQ_IF_DAY     200행 · 값은 매장마다 두 배

[단계별 비용 — 평소 하루]
  S1 0.4초 · S2 0.2초 · S3 0.1초 · S4 0.3초 · S5 6분 40초 (외부 연동 대기)
  언두: S1 ~ S4 합계 1MB 안쪽 · 잠금: S2가 SHOP_MON 12월 200행, S3가 새 전표 행

문제 ​

  1. 처음부터 다시 돌린 뒤 단계마다 무엇이 어떻게 틀어졌는지(특히 누계가 세 번, 전표가 세 장이 된 까닭)를 설명하고, 다섯 단계 각각이 '다시 돌려도 결과가 같은지' 판정하시오.
  2. (가) 체인 전체를 한 트랜잭션으로 묶는 안과 (나) 단계마다 커밋하되 단계를 멱등하게 고치고 단계 기록을 남겨 실패한 단계부터 다시 돌리는 안을, 실패했을 때의 상태, 다시 돌리는 비용, 잠금과 언두, 외부 연동으로 비교하고 하나를 고르시오.
  3. 고른 안으로 체인을 다시 작성하시오(S1 ~ S3과 재시작 제어). 오늘 오후 청구 전에 12/26분을 바로잡는 방법도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자