테마
유통 본사 월 마감 배치는 매월 1일 새벽에 지난달 판매를 요약 테이블 세 개에 넣는다. 매장 월 매출(CF_SHP_MON_SLS), 상품 월 판매(CF_ITM_MON_SLS), 요일 월 매출(CF_DOW_MON_SLS)이다. 세 문장은 묶는 기준만 다르고 모두 같은 달의 CF10과 CF11을 조인한다. 배치 체인의 단계 3, 5, 7이라 사이에 다른 단계가 끼어 02시 05분, 21분, 38분에 따로 돈다.
재무팀이 6월 마감을 보다가 매장 월 매출의 판매 건수 합계(20,550건)와 요일 월 매출의 판매 건수 합계(20,553건)가 다르다고 알려 왔다. 매장 두 곳의 POS는 밤에 꺼져 있다가 새벽에 켜지면서 지난 판매를 몰아서 올린다. 배치 담당 오과장은 "세 문장을 하나로 줄일 수 있으면 숫자도 시간도 같이 해결되지 않겠나"라고 묻는다.
CF10 판매: 500,000행 · 4,583블록 · CF10_PK (SLE_NO) · SLE_DT VARCHAR2(8) · SLE_DOW 요일('1' ~ '7') · SHP_NO 매장 6곳. 2023년 6월 판매는 20,550건이고 SLE_DT로 시작하는 인덱스는 없다.CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · 6월 판매상품은 45,210줄(상품 88개)이다.COUNT(DISTINCT a.SLE_NO)로 센다.-- 월 마감 · :ym = '202306'
-- [단계 3 · 02:05] 매장 월 매출
INSERT INTO CF_SHP_MON_SLS (SLE_YM, SHP_NO, SLE_CNT, SLE_AMT)
SELECT :ym, a.SHP_NO, COUNT(DISTINCT a.SLE_NO), SUM(b.SLE_QTY * b.SLE_UPRC)
FROM CF10 a, CF11 b
WHERE a.SLE_DT LIKE :ym || '%'
AND b.SLE_NO = a.SLE_NO
GROUP BY a.SHP_NO;
COMMIT;
-- [단계 5 · 02:21] 상품 월 판매
INSERT INTO CF_ITM_MON_SLS (SLE_YM, ITM_NO, SLE_QTY, SLE_AMT)
SELECT :ym, b.ITM_NO, SUM(b.SLE_QTY), SUM(b.SLE_QTY * b.SLE_UPRC)
FROM CF10 a, CF11 b
WHERE a.SLE_DT LIKE :ym || '%'
AND b.SLE_NO = a.SLE_NO
GROUP BY b.ITM_NO;
COMMIT;
-- [단계 7 · 02:38] 요일 월 매출
INSERT INTO CF_DOW_MON_SLS (SLE_YM, SLE_DOW, SLE_CNT, SLE_AMT)
SELECT :ym, a.SLE_DOW, COUNT(DISTINCT a.SLE_NO), SUM(b.SLE_QTY * b.SLE_UPRC)
FROM CF10 a, CF11 b
WHERE a.SLE_DT LIKE :ym || '%'
AND b.SLE_NO = a.SLE_NO
GROUP BY a.SLE_DOW;
COMMIT;
[단계 3 · 매장 월 매출 (단계 5는 2번 줄이 HASH GROUP BY, 단계 7은 같은 모양)]
--------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
--------------------------------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 1 | | 0 |00:00:00.91 | 12803 | |
| 1 | LOAD TABLE CONVENTIONAL | CF_SHP_MON_SLS | 1 | | 0 |00:00:00.91 | 12803 | |
| 2 | SORT GROUP BY | | 1 | 6 | 6 |00:00:00.91 | 12787 | 2154K (0)|
|* 3 | HASH JOIN | | 1 | 45724 | 45210 |00:00:00.84 | 12787 | 1972K (0)|
|* 4 | TABLE ACCESS FULL | CF10 | 1 | 20786 | 20550 |00:00:00.04 | 4583 | |
| 5 | TABLE ACCESS FULL | CF11 | 1 | 1096K| 1096K|00:00:00.12 | 8204 | |
--------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("B"."SLE_NO"="A"."SLE_NO")
4 - filter("A"."SLE_DT" LIKE :YM||'%')
[세 단계] 단계 3 · 12,803 단계 5 · 12,881 단계 7 · 12,804 합계 Buffers 38,488 · 경과 2.7초
[대조 · 6월] 단계 3 판매 건수 합 20,550 · 단계 7 판매 건수 합 20,553 · 세 요약의 금액 합이 모두 다르다