테마
유통 본사는 발주상품마다 입고된 수량(RCV_QTY)을 관리한다. 입고가 들어오면 그 상품의 발주 중 오래된 것부터 채운다(선입선출). 지난주 입고 자료 일부가 두 번 올라온 사고가 있어서, 사고분을 지운 입고 이력으로 RCV_QTY를 처음부터 다시 계산해야 한다.
기존 재계산 프로그램은 입고 줄마다 그 상품의 발주를 오래된 순서로 읽어 가며 채우는데, 리허설에서 41초가 걸렸다. 담당자: "앞 줄에서 얼마 채웠는지에 따라 다음 줄이 달라지니까 한 문장으로는 안 돼요." 재계산은 토요일 06:00 ~ 06:30 점검 시간에 하고, 그동안 발주와 입고 입력을 막는다.
CF12 발주: 734행 · 10블록 · PK ORD_NO · ORD_DT VARCHAR2(8)CF13 발주상품: 7,102행 · 57블록 · PK (ORD_NO, ITM_NO) · ORD_QTY. 이 문제에서는 입고 배분 수량 RCV_QTY 칸이 더 있다. ITM_NO만으로 찾을 인덱스는 없다.CF15 입출고상품: 51,497행 · 349블록 · PK (INOUT_NO, ITM_NO) · INOUT_QTY. 이 문제에서는 입출고 구분 INOUT_TY_CD('I' 입고 · 'O' 출고)를 입출고 머리 테이블에서 옮겨 둔 칸이 더 있다. 입고 줄은 30,212행이다(사고분을 지운 뒤).CF13의 복사본(CF13_C)을 만들어도 된다.PROCEDURE REBUILD_RCV IS
v_left NUMBER;
v_fill NUMBER;
BEGIN
UPDATE CF13 SET RCV_QTY = 0;
FOR g IN (SELECT INOUT_NO, ITM_NO, INOUT_QTY
FROM CF15
WHERE INOUT_TY_CD = 'I'
ORDER BY INOUT_NO) LOOP -- 입고 줄마다 (30,212번)
v_left := g.INOUT_QTY;
FOR d IN (SELECT d.ROWID AS rid, d.ORD_QTY - d.RCV_QTY AS OPEN_QTY
FROM CF13 d, CF12 h
WHERE h.ORD_NO = d.ORD_NO
AND d.ITM_NO = g.ITM_NO
AND d.RCV_QTY < d.ORD_QTY
ORDER BY h.ORD_DT, d.ORD_NO) LOOP -- 오래된 발주부터
EXIT WHEN v_left = 0;
v_fill := LEAST(v_left, d.OPEN_QTY);
UPDATE CF13 SET RCV_QTY = RCV_QTY + v_fill WHERE ROWID = d.rid;
v_left := v_left - v_fill;
END LOOP; -- 남는 수량은 초과 입고 화면이 따로 계산한다
END LOOP;
COMMIT;
END;
[리허설 — 세션 통계 · REBUILD_RCV 한 번]
경과 시간 40.6 ~ 41.9 초
recursive calls 약 52,900
execute count 약 52,700 (안쪽 커서 OPEN 30,212 · UPDATE 22,481 · 그 밖)
session logical reads 약 2,098,000
sorts (memory) 30,214
[V$SQL — 안쪽 커서]
EXECUTIONS 30,212 · BUFFER_GETS 2,024,204 (한 번에 67블록: CF13 FULL 57 · CF12 FULL 10) · ELAPSED 39.8 초
[안쪽 커서 한 번의 실행계획 — DISPLAY_CURSOR (ALLSTATS LAST)]
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 21 |00:00:00.01 | 67 | |
| 1 | SORT ORDER BY | | 1 | 33 | 21 |00:00:00.01 | 67 | 2048 (0)|
|* 2 | HASH JOIN | | 1 | 33 | 21 |00:00:00.01 | 67 | 1245K (0)|
| 3 | TABLE ACCESS FULL| CF12 | 1 | 734 | 734 |00:00:00.01 | 10 | |
|* 4 | TABLE ACCESS FULL| CF13 | 1 | 33 | 21 |00:00:00.01 | 57 | |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("H"."ORD_NO"="D"."ORD_NO")
4 - filter(("D"."ITM_NO"=:B1 AND "D"."RCV_QTY"<"D"."ORD_QTY"))
V$SQL과 실행계획으로 설명하시오.