테마
본사 레거시 유통의 월 마감 배치에는 「상품별 월 판매 집계」 단계가 있다. 2023년 6월분은 7.6초가 걸렸다. 다음 달에 신상품 40개가 들어온다는 공지가 나오자 배치 담당자가 물었다. "상품이 늘면 집계 시간도 그만큼 느는 건가요?" 소스를 열어 보니 상품 마스터를 한 건씩 돌면서, 상품마다 그 달 판매를 합계 내는 SELECT를 따로 실행하고 있었다.
CF10 판매: 500,000행 · 4,583블록 · SLE_DT VARCHAR2(8) · 2023년 6월 20,953건CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · 6월분 45,912행CF01 상품: 109행 · 5블록 · PK ITM_NO · 6월에 팔린 상품은 107개다.CF10_PK (SLE_NO)와 IX_CF10_SLE_DT (SLE_DT)(03화에서 만든 것)이다. CF11에는 PK 말고 인덱스가 없다.CF11_MON_SUM(집계 결과, 이 문제용 테이블): PK (SLE_YM, ITM_NO) · 배치는 그 달 행을 지우고 다시 넣는다. 통계는 최신이다.PROCEDURE SUM_ITEM_MONTH(p_ym VARCHAR2) IS -- p_ym = '202306'
v_qty NUMBER;
v_amt NUMBER;
BEGIN
DELETE FROM CF11_MON_SUM WHERE SLE_YM = p_ym;
FOR r IN (SELECT ITM_NO FROM CF01) LOOP -- 상품 109개를 하나씩
SELECT SUM(b.SLE_QTY), SUM(b.SLE_QTY * b.SLE_UPRC)
INTO v_qty, v_amt
FROM CF10 a, CF11 b
WHERE b.SLE_NO = a.SLE_NO
AND a.SLE_DT BETWEEN p_ym || '01' AND p_ym || '31'
AND b.ITM_NO = r.ITM_NO;
IF v_qty > 0 THEN -- 팔린 상품만 넣는다
INSERT INTO CF11_MON_SUM (SLE_YM, ITM_NO, SLE_QTY, SLE_AMT)
VALUES (p_ym, r.ITM_NO, v_qty, v_amt);
END IF;
END LOOP;
COMMIT;
END;
[세션 통계 — SUM_ITEM_MONTH('202306') 한 번]
경과 시간 7.4 ~ 7.8 초
session logical reads 약 908,600
recursive calls 약 230
execute count 약 220
[V$SQL — 루프 안의 SELECT]
SQL_TEXT EXECUTIONS BUFFER_GETS ELAPSED
SELECT SUM(B.SLE_QTY), SUM(B.SLE_QTY * B.SLE_UPRC) FROM CF10 A … 109 907,970 7.5 초
[그 SELECT 한 번의 실행계획 — DISPLAY_CURSOR (ALLSTATS LAST)]
---------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.07 | 8330 | |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.07 | 8330 | |
|* 2 | HASH JOIN | | 1 | 421 | 430 |00:00:00.07 | 8330 | 1824K (0)|
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| CF10 | 1 | 20953 | 20953 |00:00:00.01 | 257 | |
|* 4 | INDEX RANGE SCAN | IX_CF10_SLE_DT | 1 | 20953 | 20953 |00:00:00.01 | 62 | |
|* 5 | TABLE ACCESS FULL | CF11 | 1 | 10062 | 10114 |00:00:00.06 | 8073 | |
---------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"."SLE_NO"="A"."SLE_NO")
4 - access("A"."SLE_DT">=:B1||'01' AND "A"."SLE_DT"<=:B1||'31')
5 - filter("B"."ITM_NO"=:B2)
V$SQL과 실행계획으로 설명하고, 상품이 40개 늘면 어떻게 되는지 쓰시오.