테마
본사 레거시 유통의 판매 마감 패키지 PKG_SLE_DAY를 이번 달부터 튜닝팀이 맡았다. 박팀장은 인수 첫 주에 패키지 안의 힌트를 모두 점검하라고 했다. 힌트가 있는 SQL은 넷이고, 오과장이 운영에서 SQL마다 실행계획과 Hint Report를 떠 왔다.
박팀장의 지시는 이렇다. "SQL마다 힌트가 먹었는지, 먹었다면 맞는지 판정하고, 고칠 것은 고쳐 오세요. 같은 일이 안 생기게 팀 규칙도 같이."
CF10 판매: 500,000행 · 4,583블록 · CF10_PK (SLE_NO) · IX_CF10_SLE_DT (SLE_DT) · 날짜순 적재 · 하루 약 685건 · 매장 6곳CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · 영수증당 평균 2.19줄SLE_DAY_ITM 일 상품 마감: S1의 적재 대상 · 매일 밤 한 번 적재하고 낮에는 읽기만 한다PUP 계정 소유다. S3만 다른 계정의 프로그램에서 옮겨 와서 테이블 앞에 스키마 이름을 붙여 썼다SLE_DT가 VARCHAR2(8)이라 범위 조건은 실제의 4분의 1 안팎으로 추정된다(교재 03화)-- [S1] 일 상품 마감 적재 (매일 밤 한 번, 전날 하루)
INSERT /*+ APPEND LEADING(a b) USE_HASH(b) */ INTO SLE_DAY_ITM (SLE_DT, SHP_NO, ITM_NO, SLE_QTY, SLE_AMT)
SELECT a.SLE_DT, a.SHP_NO, b.ITM_NO, SUM(b.SLE_QTY), SUM(b.SLE_QTY * b.SLE_UPRC)
FROM CF10 a, CF11 b
WHERE a.SLE_DT = :d
AND b.SLE_NO = a.SLE_NO
GROUP BY a.SLE_DT, a.SHP_NO, b.ITM_NO;
-- [S2] 매장 일 영수증 상세 (점장 화면, 하루 2천 번)
SELECT /*+ ORDERED USE_HASH(a) LEADING(a b) USE_NL(b) */
a.SLE_NO, a.SLE_HMS, b.ITM_NO, b.SLE_QTY, b.SLE_UPRC
FROM CF11 b, CF10 a
WHERE a.SLE_DT = :d
AND a.SHP_NO = :shp
AND b.SLE_NO = a.SLE_NO
ORDER BY a.SLE_NO, b.ITM_NO;
-- [S3] 주간 상품 판매 (영업팀, 하루 수십 번)
SELECT /*+ LEADING(PUP.CF10 PUP.CF11) USE_HASH(PUP.CF11) FULL(PUP.CF11) */
PUP.CF11.ITM_NO, SUM(PUP.CF11.SLE_QTY) AS qty
FROM PUP.CF10, PUP.CF11
WHERE PUP.CF10.SLE_DT BETWEEN :d1 AND :d2
AND PUP.CF11.SLE_NO = PUP.CF10.SLE_NO
GROUP BY PUP.CF11.ITM_NO;
-- [S4] 영수증 한 장 상세 (고객센터, 하루 3천 번)
SELECT /*+ LEADING(a b) USE_NL(b) */
a.SLE_NO, a.SLE_DT, a.SLE_HMS, b.ITM_NO, b.SLE_QTY, b.SLE_UPRC
FROM CF10 a, CF11 b
WHERE a.SLE_NO = :sle_no
AND b.SLE_NO = a.SLE_NO;
[요약 · 운영 실측]
SQL Hint Report 계획 Buffers 시간
S1 APPEND 쓰임 · LEADING(a b), USE_HASH(b)는 N LOAD AS SELECT ← NL (CF10 하루 → CF11_PK) 3,573 0.02초
S2 ORDERED, USE_HASH(a) 쓰임 · LEADING(a b), USE_NL(b)는 U HASH JOIN (CF11 FULL이 build) 8,222 0.46초
S3 LEADING, USE_HASH, FULL 셋 다 N NL (CF10 일주일 → CF11_PK) 24,997 0.19초
S4 LEADING(a b), USE_NL(b) 쓰임 NL · 힌트를 뗀 판도 같은 plan hash value 9 0.00초
(참고) S1의 SELECT만 떼어 USE_HASH(b)로 돌리면 8,222블록
[S1 · Hint Report]
Total hints for statement: 3 (N - Unresolved (2))
1 - INS$1
N - LEADING(a b)
N - USE_HASH(b)
1 - INS$1 / SLE_DAY_ITM@INS$1
- APPEND
[S2 · Hint Report]
Total hints for statement: 4 (U - Unused (2))
1 - SEL$1
U - LEADING(a b)
- ORDERED
3 - SEL$1 / "B"@"SEL$1"
U - USE_NL(b)
4 - SEL$1 / "A"@"SEL$1"
- USE_HASH(a)
[S3 · Hint Report]
Total hints for statement: 3 (N - Unresolved (3))
1 - SEL$1
N - FULL(PUP.CF11)
N - LEADING(PUP.CF10 PUP.CF11)
N - USE_HASH(PUP.CF11)
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
[S2 · 매장 1003, 2023-12-24]
| 0 | SELECT STATEMENT | | 1 | | 251 |00:00:00.46 | 8222 | |
| 1 | SORT ORDER BY | | 1 | 251 | 251 |00:00:00.46 | 8222 | 2048 (0)|
|* 2 | HASH JOIN | | 1 | 251 | 251 |00:00:00.46 | 8222 | 38M (0)|
| 3 | TABLE ACCESS FULL | CF11 | 1 | 1096K | 1096K |00:00:00.11 | 8204 | |
|* 4 | TABLE ACCESS BY INDEX ROWID BATCHED | CF10 | 1 | 114 | 114 |00:00:00.01 | 18 | |
|* 5 | INDEX RANGE SCAN | IX_CF10_SLE_DT | 1 | 685 | 685 |00:00:00.01 | 4 | |
[S3 · 2023-12-18 ~ 2023-12-24]
| 0 | SELECT STATEMENT | | 1 | | 109 |00:00:00.19 | 24997 | |
| 1 | HASH GROUP BY | | 1 | 109 | 109 |00:00:00.19 | 24997 | 1210K (0)|
| 2 | NESTED LOOPS | | 1 | 2626 | 10501 |00:00:00.18 | 24997 | |
| 3 | NESTED LOOPS | | 1 | 2626 | 10501 |00:00:00.09 | 14497 | |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| CF10 | 1 | 1199 | 4795 |00:00:00.01 | 112 | |
|* 5 | INDEX RANGE SCAN | IX_CF10_SLE_DT | 1 | 1199 | 4795 |00:00:00.01 | 14 | |
|* 6 | INDEX RANGE SCAN | CF11_PK | 4795 | 2 | 10501 |00:00:00.06 | 14385 | |
| 7 | TABLE ACCESS BY INDEX ROWID | CF11 | 10501 | 2 | 10501 |00:00:00.08 | 10500 | |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
[S2] 2 - access("B"."SLE_NO"="A"."SLE_NO")
4 - filter("A"."SHP_NO"=:SHP)
5 - access("A"."SLE_DT"=:D)
[S3] 5 - access("CF10"."SLE_DT">=:D1 AND "CF10"."SLE_DT"<=:D2)
6 - access("CF11"."SLE_NO"="CF10"."SLE_NO")