Skip to content
튜닝 연습파티션
PART-048

2013년 시간대별 메뉴 판매 집계가 두 테이블 모두 12칸만 읽는데도 TEMP를 22MB 쓴다

기초SELECT버거423 / 700

상황 ​

버거 본사 메뉴개발팀은 해마다 1월에 지난해 「시간대별 메뉴 판매」를 뽑아 아침 메뉴 개편에 쓴다. 지난해 조민우가 주문상품 쪽에도 연도 조건을 넣어 두 테이블 모두 그해 12칸만 읽게 고쳤다. 올해(2014년 1월)도 3초 가까이 걸린다. 실행계획을 보니 칸은 12개씩만 열었는데, 해시 조인이 TEMP를 22MB 썼다.

테이블과 인덱스 ​

  • ORD_RANGE 주문(파티션 복사본, 교재 14화): 1,000,000행 · PARTITION BY RANGE (ORD_YM) 월별 25칸(P201201 ~ P201312과 빈 P_DEFAULT). 2013년은 13 ~ 24번째 칸이고 약 500,000행이다. 칸 하나 FULL ≈ 1,980블록, 12칸이면 23,760블록이다.
  • ORD_ITEM_RANGE 주문상품(파티션 복사본): ORD_ITEM 2,472,717행을 같은 키, 같은 경계(PARTITION BY RANGE (ORD_YM), 25칸)로 나눴다. 2013년은 약 1,236,000행이고 칸 하나 FULL ≈ 3,310블록, 12칸이면 39,720블록이다.
  • 주문상품의 ORD_YM은 늘 그 주문의 ORD_YM과 같다(적재할 때 주문에서 가져왔다).
  • 이 조회에 쓰이는 인덱스는 없다. 자동 PGA 관리를 쓰고, 이 세션의 해시 조인 작업 영역은 약 10MB까지 쓸 수 있다. 통계는 최신이다.

원본 SQL ​

sql
SELECT SUBSTR(o.ORD_HMS, 1, 2) AS hh, i.ITEM_ID,
       COUNT(*) AS line_cnt, SUM(i.ORD_ITEM_QTY) AS qty
  FROM ORD_RANGE o, ORD_ITEM_RANGE i
 WHERE o.ORD_YM BETWEEN '201301' AND '201312'
   AND i.ORD_YM BETWEEN '201301' AND '201312'
   AND i.ORD_NO = o.ORD_NO
 GROUP BY SUBSTR(o.ORD_HMS, 1, 2), i.ITEM_ID
 ORDER BY hh, qty DESC

실행계획 학습용 예시 · 교재 14화 규모 ​

xplan
---------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Starts | E-Rows | A-Rows |      A-Time | Buffers | Used-Mem   | Used-Tmp | Pstart | Pstop |
---------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |      1 |        |   1656 | 00:00:02.87 |   63480 |            |          |        |       |
|   1 |  SORT ORDER BY              |                |      1 |   1656 |   1656 | 00:00:02.87 |   63480 |  124K (0)  |          |        |       |
|   2 |   HASH GROUP BY             |                |      1 |   1656 |   1656 | 00:00:02.86 |   63480 | 1261K (0)  |          |        |       |
|*  3 |    HASH JOIN                |                |      1 |  1236K |  1236K | 00:00:02.41 |   63480 | 9883K (1)  |      22M |        |       |
|   4 |     PARTITION RANGE ITERATOR|                |      1 |   500K |   500K | 00:00:00.12 |   23760 |            |          |     13 |    24 |
|*  5 |      TABLE ACCESS FULL      | ORD_RANGE      |     12 |   500K |   500K | 00:00:00.09 |   23760 |            |          |     13 |    24 |
|   6 |     PARTITION RANGE ITERATOR|                |      1 |  1236K |  1236K | 00:00:00.31 |   39720 |            |          |     13 |    24 |
|*  7 |      TABLE ACCESS FULL      | ORD_ITEM_RANGE |     12 |  1236K |  1236K | 00:00:00.24 |   39720 |            |          |     13 |    24 |
---------------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("I"."ORD_NO"="O"."ORD_NO")
   5 - filter(("O"."ORD_YM">='201301' AND "O"."ORD_YM"<='201312'))
   7 - filter(("I"."ORD_YM">='201301' AND "I"."ORD_YM"<='201312'))

[세션 통계]
  physical writes direct temporary tablespace  약 2,800블록 · physical reads direct temporary tablespace  약 2,800블록

문제 ​

  1. 두 테이블 모두 12칸만 읽는데도 해시 조인이 TEMP를 쓴 까닭을 실행계획의 3번 줄과 조인 조건으로 설명하시오.
  2. 결과가 바뀌지 않게 SQL을 고쳐 두 테이블이 같은 달 칸끼리 조인하게 하고, 실행계획이 어떻게 바뀌는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자