테마
구매팀의 「월말 수불 점검」 배치는 품목마다 그달 판매 수량, 발주 수량, 월말 재고를 한 줄로 모아 CF_ITM_MON_CHK에 넣는다. 셋 중 어느 하나만 있는 품목도 빠지면 안 되어서 FULL OUTER JOIN 두 개로 이었다.
2023년 12월부터 매장 재고(CF18)에 원재료도 올리기 시작했는데, 그달 배치가 ORA-01400: cannot insert NULL into ("PUP"."CF_ITM_MON_CHK"."ITM_NO")로 멈췄다. 오과장은 SELECT만 따로 돌려 보니 129줄이 나왔다며 "세 집합을 합쳐도 품목은 109개인데 왜 129줄인지, 고치는 방법을 비교해서 가져와"라고 했다.
CF01 상품: 109행 · 5블록 · 판매상품 88 · 추가상품 1(샷추가) · 원재료 20CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · SLE_NO 앞 8자리가 판매일자 · 2023년 12월 46,322줄(판매상품 88개)CF12 발주: 734행 · 10블록 · ORD_DT VARCHAR2(8) · 12월 62건 / CF13 발주상품: 7,102행 · 57블록 · 12월 604줄(원재료 20개, 판매상품 27개)CF18 일별상품재고: 408행 · 6블록 · PK (SHP_NO, ITM_NO, INV_BS_DT) · 2023-12-31 기준 136행(68개 품목: 원재료 20, 판매상품 47, 마스터에서 지운 단종 품목 1)CF_ITM_MON_CHK 점검 테이블: PK (CHK_YM, ITM_NO) · ITM_NO는 NOT NULL · 통계 최신:v_from = '20231201' · :v_to = '20240101' · :v_last = '20231231'INSERT INTO CF_ITM_MON_CHK (CHK_YM, ITM_NO, SLE_QTY, ORD_QTY, INV_QTY)
SELECT :v_ym, NVL(s.ITM_NO, o.ITM_NO), s.qty, o.qty, k.qty
FROM (SELECT ITM_NO, SUM(SLE_QTY) AS qty
FROM CF11
WHERE SLE_NO >= :v_from AND SLE_NO < :v_to
GROUP BY ITM_NO) s
FULL OUTER JOIN
(SELECT d.ITM_NO, SUM(d.ORD_QTY) AS qty
FROM CF12 h, CF13 d
WHERE h.ORD_DT BETWEEN :v_from AND :v_last
AND d.ORD_NO = h.ORD_NO
GROUP BY d.ITM_NO) o
ON o.ITM_NO = s.ITM_NO
FULL OUTER JOIN
(SELECT ITM_NO, SUM(INV_QTY) AS qty
FROM CF18
WHERE INV_BS_DT = :v_last
GROUP BY ITM_NO) k
ON k.ITM_NO = s.ITM_NO
[SELECT만 따로 돌린 계획, 129줄]
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 129 |00:00:00.04 | 967 |
| 1 | VIEW | VW_FOJ_1 | 1 | 129 | 129 |00:00:00.04 | 967 |
|* 2 | HASH JOIN FULL OUTER | | 1 | 129 | 129 |00:00:00.04 | 967 |
| 3 | VIEW | | 1 | 68 | 68 |00:00:00.01 | 6 |
| 4 | HASH GROUP BY | | 1 | 68 | 68 |00:00:00.01 | 6 |
|* 5 | TABLE ACCESS FULL | CF18 | 1 | 136 | 136 |00:00:00.01 | 6 |
| 6 | VIEW | VW_FOJ_0 | 1 | 108 | 108 |00:00:00.04 | 961 |
|* 7 | HASH JOIN FULL OUTER | | 1 | 108 | 108 |00:00:00.04 | 961 |
| 8 | VIEW | | 1 | 47 | 47 |00:00:00.01 | 67 |
| 9 | HASH GROUP BY | | 1 | 47 | 47 |00:00:00.01 | 67 |
|* 10 | HASH JOIN | | 1 | 600 | 604 |00:00:00.01 | 67 |
|* 11 | TABLE ACCESS FULL | CF12 | 1 | 61 | 62 |00:00:00.01 | 10 |
| 12 | TABLE ACCESS FULL | CF13 | 1 | 7102 | 7102 |00:00:00.01 | 57 |
| 13 | VIEW | | 1 | 88 | 88 |00:00:00.03 | 894 |
| 14 | HASH GROUP BY | | 1 | 88 | 88 |00:00:00.03 | 894 |
| 15 | TABLE ACCESS BY INDEX ROWID | CF11 | 1 | 45980 | 46322 |00:00:00.02 | 894 |
|* 16 | INDEX RANGE SCAN | CF11_PK | 1 | 45980 | 46322 |00:00:00.01 | 181 |
-----------------------------------------------------------------------------------------------------------
2 - access("K"."ITM_NO"="S"."ITM_NO")
5 - filter("INV_BS_DT"=:V_LAST)
7 - access("O"."ITM_NO"="S"."ITM_NO")
10 - access("D"."ORD_NO"="H"."ORD_NO")
11 - filter(("H"."ORD_DT">=:V_FROM AND "H"."ORD_DT"<=:V_LAST))
16 - access("SLE_NO">=:V_FROM AND "SLE_NO"<:V_TO)
CF01을 기준으로 세 집합을 LEFT JOIN. 결과 줄 수, 읽는 블록, 부작용을 쓰시오.