테마
버거 본사의 「일 매출 마감」 배치는 매일 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는 자율 트랜잭션으로 로그만 남긴다. 배치 본문은 자율 트랜잭션이 아니다.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;
[배치 로그 — 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 ← 이 행들을 확정한 커밋의 시각