테마
본사 DW 연동 배치 P_SEND_CF10은 매일 02시에 판매(CF10) 전체를 DW로 보낸다. DW 쪽 수신 API가 한 번에 5,000건까지만 받아서, 개발자는 판매번호 순으로 정렬해 5,000건씩 OFFSET으로 잘라 보냈다. 첫 묶음은 0.01초인데 마지막 묶음은 0.7초가 걸리고, DB 쪽에서만 35초를 쓴다.
DW 담당자는 다른 문제도 알려 왔다. "판매 몇 건이 같은 날 두 번 들어오고, 어떤 판매는 그날 빠졌다가 다음 날 들어온다." 판매는 야간에도 들어오고(POS 지연 전송분은 원래 판매일의 판매번호를 받는다), 취소된 판매는 지워진다.
CF10 판매: 500,000행 · 4,583블록 · SLE_NO VARCHAR2(15) ('20231231-0612', 앞 8자리가 판매일자) · SLE_DT · SLE_HMS · SLE_DOW · SHP_NOCF10_PK (SLE_NO): 높이 3 · 리프 약 1,700블록 · 판매번호 순서와 쌓인 순서가 거의 같다(클러스터링 팩터 9,340).UNDO_RETENTION은 900초다. 통계는 최신이다.PROCEDURE P_SEND_CF10 IS
TYPE t_tab IS TABLE OF CF10%ROWTYPE;
v_buf t_tab;
v_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO v_cnt FROM CF10;
FOR k IN 0 .. CEIL(v_cnt / 5000) - 1 LOOP
SELECT *
BULK COLLECT INTO v_buf
FROM CF10
ORDER BY SLE_NO
OFFSET k * 5000 ROWS FETCH NEXT 5000 ROWS ONLY;
DW_API.SEND_CHUNK(v_buf);
END LOOP;
END;
[TKPROF 요약 · P_SEND_CF10 한 번]
SELECT COUNT(*) FROM CF10
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.05 0.05 0 1712 0 1
SELECT * FROM CF10 ORDER BY SLE_NO OFFSET :B1 * 5000 ROWS FETCH NEXT 5000 ROWS ONLY
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 100 0.01 0.01 0 0 0 0
Fetch 100 34.62 35.18 0 557389 0 500000
[마지막 묶음 · k = 99] (첫 묶음 k = 0 은 같은 모양 · A-Rows 5,000 · Buffers 112)
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 5000 |00:00:00.69 | 11037 |
|* 1 | VIEW | | 1 | 5000 | 5000 |00:00:00.69 | 11037 |
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 5000 | 500K|00:00:00.62 | 11037 |
| 3 | TABLE ACCESS BY INDEX ROWID | CF10 | 1 | 500K| 500K|00:00:00.41 | 11037 |
| 4 | INDEX FULL SCAN | CF10_PK | 1 | 5000 | 500K|00:00:00.08 | 1697 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("from$_subquery$_002"."rowlimit_$$_rownumber"<=CASE WHEN (:B1*5000>=0) THEN
FLOOR(TO_NUMBER(TO_CHAR(:B1*5000)))+5000 ELSE 5000 END AND
"from$_subquery$_002"."rowlimit_$$_rownumber">:B1*5000))
2 - filter(ROW_NUMBER() OVER ( ORDER BY "CF10"."SLE_NO")<=CASE WHEN (:B1*5000>=0) THEN
FLOOR(TO_NUMBER(TO_CHAR(:B1*5000)))+5000 ELSE 5000 END )
SELECT 한 번이 읽는 양이 묶음 번호에 따라 어떻게 바뀌는지 쓰고, 전체 557,389블록이 나오는 계산 근거를 보이시오.CF10을 한 번만 읽고, 묶음 사이에 판매가 들어오거나 지워져도 빠지거나 겹치지 않도록 배치를 고치시오. 고친 방식의 위험도 쓰시오.