테마
본사 레거시 유통의 월 마감에는 외주 개발사가 2018년에 만든 「협력사 월 납품 실적 보고」 체인이 있다. 판매상품을 작업 테이블에 옮기고, 행마다 협력사와 분류를 채우고, 자체 상품을 지우고, 묶고, 이름을 붙여 리포트 테이블에 넣는 여섯 단계이고 단계마다 커밋한다. 결과는 617행이다. 월 마감 창을 줄이는 작업을 맡은 오과장이 물었다. "단계마다 하나씩 튜닝하면 될까요, 아예 다시 짤까요? 다시 짜면 숫자가 지금과 똑같이 나와야 합니다. 협력사들이 이 숫자로 납품 대금을 맞춰 봐요."
CF10 판매: 500,000행 · 4,583블록 · 판매 날짜순 적재 · 2023년 6월 20,953건 · IX_CF10_SLE_DT (SLE_DT) · SHP_NO 매장 5곳CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · 6월분 45,912행CF01 상품: 109행 · 5블록 · ITM_NO · CTG_NO · PTNR_NO(협력사, 자체 상품은 'P000') · 6월에 팔린 상품 중 2개는 단종 정리로 마스터에서 지웠다(그 판매상품 87행).CF02 카테고리: 18행 · 4블록 · CF07 매장: 6행 · 4블록W_SLE_1, W_SLE_2: 이 체인만 쓰는 영구 작업 테이블(LOGGING, 인덱스 없음) · RPT_PTNR_MON: 리포트 테이블(이 문제용), 협력사 화면이 읽는다.PROCEDURE P_PTNR_MON(p_ym VARCHAR2) IS -- p_ym = '202306'
v_ptnr CF01.PTNR_NO%TYPE;
v_ctg CF01.CTG_NO%TYPE;
v_cnm CF02.CTG_NM%TYPE;
v_snm CF07.SHP_NM%TYPE;
BEGIN
-- ① 그 달 판매상품을 작업 테이블로
INSERT INTO W_SLE_1 (SLE_NO, SHP_NO, ITM_NO, SLE_QTY, SLE_UPRC)
SELECT h.SLE_NO, h.SHP_NO, d.ITM_NO, d.SLE_QTY, d.SLE_UPRC
FROM CF10 h, CF11 d
WHERE d.SLE_NO = h.SLE_NO
AND h.SLE_DT BETWEEN p_ym || '01' AND p_ym || '31';
COMMIT;
-- ② 행마다 협력사와 분류를 채운다
FOR r IN (SELECT ROWID AS rid, ITM_NO FROM W_SLE_1) LOOP
BEGIN
SELECT PTNR_NO, CTG_NO INTO v_ptnr, v_ctg FROM CF01 WHERE ITM_NO = r.ITM_NO;
EXCEPTION
WHEN NO_DATA_FOUND THEN v_ptnr := NULL; v_ctg := NULL; -- 마스터에 없는 상품은 비워 둔다
END;
UPDATE W_SLE_1 SET PTNR_NO = v_ptnr, CTG_NO = v_ctg WHERE ROWID = r.rid;
END LOOP;
COMMIT;
-- ③ 자체 상품은 보고 대상이 아니다
DELETE FROM W_SLE_1 WHERE PTNR_NO = 'P000';
COMMIT;
-- ④ 협력사 · 분류 · 매장으로 묶는다
INSERT INTO W_SLE_2 (PTNR_NO, CTG_NO, SHP_NO, SLE_QTY, SLE_AMT)
SELECT PTNR_NO, CTG_NO, SHP_NO, SUM(SLE_QTY), SUM(SLE_QTY * SLE_UPRC)
FROM W_SLE_1
GROUP BY PTNR_NO, CTG_NO, SHP_NO;
COMMIT;
-- ⑤ 이름을 붙여 리포트에
FOR r IN (SELECT * FROM W_SLE_2) LOOP
BEGIN
SELECT CTG_NM INTO v_cnm FROM CF02 WHERE CTG_NO = r.CTG_NO;
EXCEPTION
WHEN NO_DATA_FOUND THEN v_cnm := '(미분류)';
END;
SELECT SHP_NM INTO v_snm FROM CF07 WHERE SHP_NO = r.SHP_NO;
INSERT INTO RPT_PTNR_MON (SLE_YM, PTNR_NO, CTG_NO, CTG_NM, SHP_NO, SHP_NM, SLE_QTY, SLE_AMT)
VALUES (p_ym, r.PTNR_NO, r.CTG_NO, v_cnm, r.SHP_NO, v_snm, r.SLE_QTY, r.SLE_AMT);
END LOOP;
COMMIT;
-- ⑥ 작업 테이블 비우기
DELETE FROM W_SLE_1;
DELETE FROM W_SLE_2;
COMMIT;
END;
[단계별 — 2023년 6월분 · 운영 · 단독 실행]
단계 처리 행 경과 redo recursive calls 비고
① W_SLE_1 적재 45,912 0.9초 6.1 MB 12 CF10 · CF11 해시 조인 12,787블록
② 협력사 · 분류 채우기 45,912 9.8초 14.2 MB 91,830 행마다 CF01 SELECT INTO + ROWID UPDATE
③ 자체 상품 지우기 6,017 0.4초 2.9 MB 6
④ W_SLE_2 집계 617 0.2초 0.1 MB 4
⑤ 리포트 적재 617 0.3초 0.2 MB 1,858 행마다 CF02 · CF07 SELECT INTO + INSERT
⑥ 작업 테이블 비우기 40,512 1.1초 11.6 MB 4 W_SLE_1 39,895 + W_SLE_2 617
합계 12.7초 35.1 MB 93,714 커밋 6번
[6월 리포트에 든 것]
617행 · 그중 PTNR_NO 가 빈 행 3행 (마스터에 없는 상품 87행이 '(미분류)'로 묶인 것)