테마
버거원 본사는 카드사의 요청으로 2013년 12월 주문 전부의 카드 승인 내역을 다시 대사한다. 주문 한 건마다 카드사 중계 서버에 승인 내역을 묻고 결과를 대사 테이블에 적는데, 한 건에 평균 18ms가 걸린다(대부분 중계 서버의 응답 대기). 중계 서버는 동시 연결을 8개까지 받는다.
개발자는 DBMS_PARALLEL_EXECUTE로 주문번호를 8조각으로 나눠 작업 8개로 돌렸다. 그런데 작업 7개는 1초 안에 끝났고 한 작업만 12분 48초를 돌았다. 오과장: "한 줄로 돌린 것과 똑같잖아요. 작업을 16개로 늘리면 될까요?"
ORD: 1,000,000행 · 22,422블록(블록당 약 45행) · ORD_NO NUMBER 1 ~ 1,000,000(빈 번호 없음, 주문 일시 순으로 매겼다) · 테이블도 주문번호 순서로 쌓였다ORD_PK (ORD_NO) · ORD_X01 (ORD_DT, ORD_HMS) · 2013년 12월 주문 42,408건은 ORD_NO 957,593 ~ 1,000,000이다(ORD_X01 리프 약 140블록, 테이블 끝의 951블록).PKG_CARD_IF.RECON(p_ord_no): 주문 한 건의 승인 내역을 중계 서버에 묻고 대사 테이블 CARD_RECON(이 문제용, PK ORD_NO)에 한 행을 넣는다. 주문끼리 같은 행을 고치지 않는다.CREATE JOB 권한이 있다.-- 청크 하나가 하는 일 (RUN_TASK 가 청크마다 부르고, 끝나면 커밋한다)
PROCEDURE P_CARD_RECON(p_start NUMBER, p_end NUMBER) IS
BEGIN
FOR r IN (SELECT ORD_NO
FROM ORD
WHERE ORD_NO BETWEEN p_start AND p_end
AND ORD_DT BETWEEN '20131201' AND '20131231') LOOP
PKG_CARD_IF.RECON(r.ORD_NO); -- 중계 서버 왕복 · 평균 18ms
END LOOP;
END;
-- 작업 등록 (주문번호를 125,000씩 8조각 · 동시 작업 8개)
BEGIN
DBMS_PARALLEL_EXECUTE.CREATE_TASK('RECON_201312');
DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_NUMBER_COL('RECON_201312', 'DEV', 'ORD', 'ORD_NO', chunk_size => 125000);
DBMS_PARALLEL_EXECUTE.RUN_TASK('RECON_201312', 'BEGIN P_CARD_RECON(:start_id, :end_id); END;',
DBMS_SQL.NATIVE, parallel_level => 8);
END;
[USER_PARALLEL_EXECUTE_CHUNKS — 작업 RECON_201312]
CHUNK_ID START_ID END_ID 대상 주문 경과
1 1 125,000 0 0.3초
2 125,001 250,000 0 0.3초
…
7 750,001 875,000 0 0.3초
8 875,001 1,000,000 42,408 12분 48초
작업 전체 경과 12분 49초 · 일한 작업 수: 처음 1초 동안 8개, 그 뒤로 1개
[청크 1의 커서 — DISPLAY_CURSOR (ALLSTATS LAST)]
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.02 | 1091 |
|* 1 | TABLE ACCESS BY INDEX ROWID BATCHED| ORD | 1 | 5302 | 0 |00:00:00.02 | 1091 |
|* 2 | INDEX RANGE SCAN | ORD_X01 | 1 | 42419 | 42408 |00:00:00.01 | 140 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("ORD_NO">=:B2 AND "ORD_NO"<=:B1))
2 - access("ORD_DT">='20131201' AND "ORD_DT"<='20131231')
CREATE_CHUNKS_BY_ROWID로 바꾸면 해결되는지 쓰시오.