테마
버거원 본사의 일 마감 체인은 매일 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 롤백으로 되돌릴 수 없지만, 같은 마스터를 다시 보내도 결과는 같다.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;
[일 마감 체인 기록 — 기준일 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가 새 전표 행