테마
매달 1일 새벽 PKG_MON.P_ITEM_SUM이 지난달 상품별 판매 수량을 MON_ITEM_SUM에 싣는다. 조민우가 이 INSERT의 SELECT 부분만 떼어 SQL Developer에서 돌리면 56,336블록인데, 배치 로그의 같은 문장은 168K 블록을 읽었다.
조민우가 배치와 같은 세션 조건에서 10053 트레이스를 떴다. 패키지 맨 앞 두 줄은 2015년에 들어갔고, 커밋 메시지에는 "인덱스 우선 튜닝 가이드 적용"이라고만 적혀 있다.
ORD: 1,000,000행 · 22,422블록 · ORD_X01 (ORD_DT, ORD_HMS) 리프 3,774 · 클러스터링 팩터 22,223(날짜순 적재) · 한 달 약 41,700건ORD_DT에는 HYBRID 히스토그램이 있어 한 달 범위의 E-Rows가 실제와 비슷하다.ORD_ITEM: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) 높이 3 · 주문당 2.47줄(한 주문의 줄은 같은 블록에 있다)MON_ITEM_SUM (YM, ITEM_ID, QTY): 이 배치가 쓰는 월 집계 테이블 · 달마다 92행 · 인덱스 없음optimizer_index_cost_adj 100, optimizer_index_caching 0) · 통계 최신PROCEDURE P_ITEM_SUM(p_ym VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET OPTIMIZER_INDEX_COST_ADJ = 1'; -- 2015 인덱스 우선 튜닝 가이드
EXECUTE IMMEDIATE 'ALTER SESSION SET OPTIMIZER_INDEX_CACHING = 100';
DELETE FROM MON_ITEM_SUM WHERE YM = p_ym;
INSERT INTO MON_ITEM_SUM (YM, ITEM_ID, QTY)
SELECT p_ym, i.ITEM_ID, SUM(i.ORD_ITEM_QTY)
FROM ORD o, ORD_ITEM i
WHERE o.ORD_DT BETWEEN p_ym || '01' AND p_ym || '31'
AND i.ORD_NO = o.ORD_NO
GROUP BY i.ITEM_ID;
COMMIT;
END;
[배치 안의 INSERT — p_ym = '201311']
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 1 | | 0 |00:00:01.38 | 168K|
| 1 | LOAD TABLE CONVENTIONAL | MON_ITEM_SUM | 1 | | 0 |00:00:01.38 | 168K|
| 2 | HASH GROUP BY | | 1 | 92 | 92 |00:00:01.37 | 168K|
|* 3 | FILTER | | 1 | | 103K|00:00:01.34 | 168K|
| 4 | NESTED LOOPS | | 1 | 103K| 103K|00:00:01.33 | 168K|
| 5 | NESTED LOOPS | | 1 | 103K| 103K|00:00:00.71 | 126K|
| 6 | TABLE ACCESS BY INDEX ROWID BATCHED| ORD | 1 | 41700 | 41712 |00:00:00.03 | 1071 |
|* 7 | INDEX RANGE SCAN | ORD_X01 | 1 | 41700 | 41712 |00:00:00.01 | 139 |
|* 8 | INDEX RANGE SCAN | ORD_ITEM_PK | 41712 | 2 | 103K|00:00:00.40 | 125K|
| 9 | TABLE ACCESS BY INDEX ROWID | ORD_ITEM | 103K| 1 | 103K|00:00:00.36 | 41712 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(:B1||'01'<=:B1||'31')
7 - access("O"."ORD_DT">=:B1||'01' AND "O"."ORD_DT"<=:B1||'31')
8 - access("I"."ORD_NO"="O"."ORD_NO")
[10053 — 배치와 같은 세션 조건 · 필요한 줄만]
PARAMETERS WITH ALTERED VALUES
******************************
Compilation Environment Dump
optimizer_index_cost_adj = 1
optimizer_index_caching = 100
...
NL Join
Outer table: Card: 41700.00 Cost: 11.21 Resp: 11.21 Degree: 1
Inner table: ORD_ITEM Alias: I
Access Path: index (RangeScan)
Index: ORD_ITEM_PK
resc_io: 0.03 resc_cpu: 21934
NL Join : Cost: 1262.48 Resp: 1262.48 Degree: 1
HA Join
HA cost: 15409.66
Best:: JoinMethod: NestedLoop
Cost: 1262.48 Degree: 1 Resp: 1262.48 Card: 102999.00
[같은 SELECT — SQL Developer 세션(파라미터 기본값)] HASH JOIN · ORD_ITEM FULL · Buffers 56,336 · 0.61초
(10053 : NL Join Cost 167,9xx · HA cost 16,4xx → HASH)
(126K = 126,207 · 125K = 125,136 · 168K = 167,919)