테마
본사 영업기획팀의 「권역별 월 주문 수」는 서울, 경기, 부산 세 권역의 2013년 월별 주문 수를 요약 테이블 RGN_MON_ORD에 담는다. 매장 정보가 정정될 때마다 1년 치를 지우고 다시 넣는데, 한 번에 3.4초가 걸리고 그동안 디스크 읽기가 몰린다.
다음 달부터 대구 권역을 더해 달라는 요청이 왔다. 개발자는 "UNION ALL에 갈래 하나만 더 붙이면 된다"라고 하고, DBA는 "그러면 4.5초가 된다"라고 한다.
ORD 주문: 1,000,000행 · 22,422블록 · ORD_DT VARCHAR2(8) · 2013년 500,218건 · SHOP_NO · ORD_X01 (ORD_DT, ORD_HMS)가 있지만 1년 치를 읽을 때는 FULL이 낫다SHOP 매장: 200행 · 5블록 · ADDR 주소(앞 두 글자가 시도: 서울 62곳 · 경기 41곳 · 부산 10곳 · 그 밖 87곳)RGN_MON_ORD 권역 월 주문 (이 문제에서 쓰는 파생 테이블): RGN_CD NOT NULL · ORD_YM · ORD_CNT · 36행(3권역 × 12개월)ORD가 버퍼 캐시에 남아 있지 않다INSERT INTO RGN_MON_ORD (RGN_CD, ORD_YM, ORD_CNT)
SELECT 'SEOUL', SUBSTR(o.ORD_DT, 1, 6), COUNT(*)
FROM ORD o, SHOP s
WHERE s.SHOP_NO = o.SHOP_NO
AND s.ADDR LIKE '서울%'
AND o.ORD_DT BETWEEN '20130101' AND '20131231'
GROUP BY SUBSTR(o.ORD_DT, 1, 6)
UNION ALL
SELECT 'GYEONGGI', SUBSTR(o.ORD_DT, 1, 6), COUNT(*)
FROM ORD o, SHOP s
WHERE s.SHOP_NO = o.SHOP_NO
AND s.ADDR LIKE '경기%'
AND o.ORD_DT BETWEEN '20130101' AND '20131231'
GROUP BY SUBSTR(o.ORD_DT, 1, 6)
UNION ALL
SELECT 'BUSAN', SUBSTR(o.ORD_DT, 1, 6), COUNT(*)
FROM ORD o, SHOP s
WHERE s.SHOP_NO = o.SHOP_NO
AND s.ADDR LIKE '부산%'
AND o.ORD_DT BETWEEN '20130101' AND '20131231'
GROUP BY SUBSTR(o.ORD_DT, 1, 6)
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
------------------------------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 1 | | 0 | 00:00:03.41 | 67293 | 67266 |
| 1 | LOAD TABLE CONVENTIONAL | RGN_MON_ORD | 1 | | 0 | 00:00:03.41 | 67293 | 67266 |
| 2 | UNION-ALL | | 1 | | 36 | 00:00:03.40 | 67281 | 67266 |
| 3 | HASH GROUP BY | | 1 | 12 | 12 | 00:00:01.14 | 22427 | 22422 |
|* 4 | HASH JOIN | | 1 | 150K | 155K | 00:00:01.10 | 22427 | 22422 |
|* 5 | TABLE ACCESS FULL | SHOP | 1 | 60 | 62 | 00:00:00.01 | 5 | 0 |
|* 6 | TABLE ACCESS FULL | ORD | 1 | 500K | 500K | 00:00:00.97 | 22422 | 22422 |
| 7 | HASH GROUP BY | | 1 | 12 | 12 | 00:00:01.13 | 22427 | 22422 |
|* 8 | HASH JOIN | | 1 | 100K | 102K | 00:00:01.09 | 22427 | 22422 |
|* 9 | TABLE ACCESS FULL | SHOP | 1 | 40 | 41 | 00:00:00.01 | 5 | 0 |
|* 10 | TABLE ACCESS FULL | ORD | 1 | 500K | 500K | 00:00:00.96 | 22422 | 22422 |
| 11 | HASH GROUP BY | | 1 | 12 | 12 | 00:00:01.13 | 22427 | 22422 |
|* 12 | HASH JOIN | | 1 | 25009 | 25011 | 00:00:01.09 | 22427 | 22422 |
|* 13 | TABLE ACCESS FULL | SHOP | 1 | 10 | 10 | 00:00:00.01 | 5 | 0 |
|* 14 | TABLE ACCESS FULL | ORD | 1 | 500K | 500K | 00:00:00.96 | 22422 | 22422 |
------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("S"."SHOP_NO"="O"."SHOP_NO")
5 - filter("S"."ADDR" LIKE '서울%')
6 - filter(("O"."ORD_DT">='20130101' AND "O"."ORD_DT"<='20131231'))
8 - access("S"."SHOP_NO"="O"."SHOP_NO")
9 - filter("S"."ADDR" LIKE '경기%')
10 - filter(("O"."ORD_DT">='20130101' AND "O"."ORD_DT"<='20131231'))
12 - access("S"."SHOP_NO"="O"."SHOP_NO")
13 - filter("S"."ADDR" LIKE '부산%')
14 - filter(("O"."ORD_DT">='20130101' AND "O"."ORD_DT"<='20131231'))
ORD를 한 번만 읽도록 INSERT를 고치시오. 결과 36행이 바뀌지 않으려면 무엇을 지켜야 하는지도 쓰시오.