테마
본사 BI팀의 야간 배치는 2013년 집계 세 문장(S1 상품별 판매 수량, S2 판매 수량 상위 10개 매장, S3 월별 상품 유형 판매)을 차례로 돌린다. 세 문장을 합쳐 12초 가까이 걸리고, S2를 돌릴 때마다 TEMP 경보가 울린다. S2의 힌트는 작년에 "상세가 더 많으니 상세부터 읽어야 한다"며 넣은 것이다. 오과장은 세 문장을 하나씩 보고 고칠 것과 그대로 둘 것을 숫자로 정해 달라고 했다.
ORD 주문: 1,000,000행 · 22,422블록 · 2013년 500,218행 · SHOP_NO 200곳ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · 2013년 주문의 상품 1,236,018줄 · FK ORD_ITEM.ORD_NO → ORD (ENABLE VALIDATE)ORD_ITEM의 ORD_DT와 ORD_HMS는 POS가 주문을 넣을 때 헤더에서 복사하는 반정규화 컬럼이다. 지금 헤더와 다른 줄은 0건이지만, 이를 지키는 제약은 없다ITEM 상품: 92행 · 5블록 · ITEM_TYPE_CD 4종 / SHOP 매장: 200행 · 5블록 · SHOP_NM · ADDRpga_aggregate_target 512M · AUTO (이 시간대 해시 조인 하나의 work area는 약 100MB)-- [S1] 상품별 판매 수량
SELECT t.ITEM_ID, t.ITEM_NM, SUM(i.ORD_ITEM_QTY) AS qty
FROM ORD o, ORD_ITEM i, ITEM t
WHERE o.ORD_DT BETWEEN '20130101' AND '20131231'
AND i.ORD_NO = o.ORD_NO
AND t.ITEM_ID = i.ITEM_ID
GROUP BY t.ITEM_ID, t.ITEM_NM;
-- [S2] 판매 수량 상위 10개 매장
SELECT *
FROM (SELECT /*+ LEADING(i o) USE_HASH(o) */
s.SHOP_NO, s.SHOP_NM, s.ADDR, SUM(i.ORD_ITEM_QTY) AS qty
FROM ORD o, ORD_ITEM i, SHOP s
WHERE o.ORD_DT BETWEEN '20130101' AND '20131231'
AND i.ORD_NO = o.ORD_NO
AND s.SHOP_NO = o.SHOP_NO
GROUP BY s.SHOP_NO, s.SHOP_NM, s.ADDR
ORDER BY qty DESC)
WHERE ROWNUM <= 10;
-- [S3] 월별 상품 유형 판매
SELECT SUBSTR(i.ORD_DT, 1, 6) AS ym, t.ITEM_TYPE_CD, SUM(i.ORD_ITEM_QTY) AS qty
FROM ORD_ITEM i, ITEM t
WHERE i.ORD_DT BETWEEN '20130101' AND '20131231'
AND t.ITEM_ID = i.ITEM_ID
GROUP BY SUBSTR(i.ORD_DT, 1, 6), t.ITEM_TYPE_CD;
------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp|
------------------------------------------------------------------------------------------------------------------------------------------------
[S1]
| 0 | SELECT STATEMENT | | 1 | | 92 |00:00:02.87 | 77692 | 0 | 0 | | | | |
| 1 | HASH GROUP BY | | 1 | 92 | 92 |00:00:02.87 | 77692 | 0 | 0 | 1186K| 1186K| 1223K (0)| |
|* 2 | HASH JOIN | | 1 | 1236K| 1236K|00:00:02.41 | 77692 | 0 | 0 | 1376K| 1376K| 1270K (0)| |
| 3 | TABLE ACCESS FULL | ITEM | 1 | 92 | 92 |00:00:00.01 | 5 | 0 | 0 | | | | |
|* 4 | HASH JOIN | | 1 | 1236K| 1236K|00:00:01.98 | 77687 | 0 | 0 | 37M| 6418K| 39M (0)| |
|* 5 | TABLE ACCESS FULL | ORD | 1 | 500K| 500K|00:00:00.24 | 22422 | 0 | 0 | | | | |
| 6 | TABLE ACCESS FULL | ORD_ITEM | 1 | 2472K| 2472K|00:00:00.45 | 55265 | 0 | 0 | | | | |
[S2]
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:07.71 | 77692 | 11203 | 11203 | | | | |
|* 1 | COUNT STOPKEY | | 1 | | 10 |00:00:07.71 | 77692 | 11203 | 11203 | | | | |
| 2 | VIEW | | 1 | 200 | 10 |00:00:07.71 | 77692 | 11203 | 11203 | | | | |
|* 3 | SORT ORDER BY STOPKEY | | 1 | 200 | 10 |00:00:07.71 | 77692 | 11203 | 11203 | 2048 | 2048 | 2048 (0)| |
| 4 | HASH GROUP BY | | 1 | 200 | 200 |00:00:07.70 | 77692 | 11203 | 11203 | 1542K| 1542K| 1490K (0)| |
|* 5 | HASH JOIN | | 1 | 1236K| 1236K|00:00:07.38 | 77692 | 11203 | 11203 | 1421K| 1421K| 1290K (0)| |
| 6 | TABLE ACCESS FULL | SHOP | 1 | 200 | 200 |00:00:00.01 | 5 | 0 | 0 | | | | |
|* 7 | HASH JOIN | | 1 | 1236K| 1236K|00:00:06.95 | 77687 | 11203 | 11203 | 176M| 12M| 98M (1)| 88M|
| 8 | TABLE ACCESS FULL | ORD_ITEM | 1 | 2472K| 2472K|00:00:00.58 | 55265 | 0 | 0 | | | | |
|* 9 | TABLE ACCESS FULL | ORD | 1 | 500K| 500K|00:00:00.30 | 22422 | 0 | 0 | | | | |
[S3]
| 0 | SELECT STATEMENT | | 1 | | 48 |00:00:01.12 | 55270 | 0 | 0 | | | | |
| 1 | HASH GROUP BY | | 1 | 48 | 48 |00:00:01.12 | 55270 | 0 | 0 | 1186K| 1186K| 1210K (0)| |
|* 2 | HASH JOIN | | 1 | 1236K| 1236K|00:00:00.88 | 55270 | 0 | 0 | 1376K| 1376K| 1270K (0)| |
| 3 | TABLE ACCESS FULL | ITEM | 1 | 92 | 92 |00:00:00.01 | 5 | 0 | 0 | | | | |
|* 4 | TABLE ACCESS FULL | ORD_ITEM | 1 | 1236K| 1236K|00:00:00.47 | 55265 | 0 | 0 | | | | |
------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
[S1] 2 - access("T"."ITEM_ID"="I"."ITEM_ID")
4 - access("I"."ORD_NO"="O"."ORD_NO")
5 - filter(("O"."ORD_DT">='20130101' AND "O"."ORD_DT"<='20131231'))
[S2] 1 - filter(ROWNUM<=10)
3 - filter(ROWNUM<=10)
5 - access("S"."SHOP_NO"="O"."SHOP_NO")
7 - access("I"."ORD_NO"="O"."ORD_NO")
9 - filter(("O"."ORD_DT">='20130101' AND "O"."ORD_DT"<='20131231'))
[S3] 2 - access("T"."ITEM_ID"="I"."ITEM_ID")
4 - filter(("I"."ORD_DT">='20130101' AND "I"."ORD_DT"<='20131231'))