Skip to content
튜닝 연습조인 튜닝
JOIN-027

회계 감사용 2013년 주문 상품 추출이 TEMP를 100MB 가까이 쓰고 8초 걸린다

중급SELECT버거177 / 700

상황 ​

회계법인이 감사 자료로 2013년 주문 상품 내역을 파일로 달라고 했다. 요구한 칸은 주문번호, 주문일, 주문시각, 매장, 상품, 수량 여섯 개다. 개발자는 "나중에 칸을 더 달라고 할지 몰라서" 주문 헤더를 o.*로 뽑았다. 추출을 돌릴 때마다 TEMP 사용 경보가 울린다. 오과장은 "블록은 두 테이블을 한 번씩 읽은 만큼이라 정상인데, PGA를 늘려야 하나"라고 묻는다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · 한 행이 약 180바이트 (ORD_NO · ORD_DT · ORD_HMS · SHOP_NO 말고 문자열 채움 컬럼이 여럿 있다) · 2013년 500,218행
  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · 2013년 주문의 상품 1,236,018줄
  • pga_aggregate_target 512M · AUTO · 이 시간대에 해시 조인 하나가 받을 수 있는 work area는 약 100MB · 통계 최신

원본 SQL ​

sql
SELECT o.*, i.ITEM_ID, i.ORD_ITEM_QTY
  FROM ORD o, ORD_ITEM i
 WHERE o.ORD_DT BETWEEN '20130101' AND '20131231'
   AND i.ORD_NO = o.ORD_NO

실행계획 학습용 예시 ​

xplan
-------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
-------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |          |      1 |        |   1236K|00:00:07.93 |   77687 | 11950 |  11950 |       |       |          |         |
|*  1 |  HASH JOIN         |          |      1 |   1236K|   1236K|00:00:07.93 |   77687 | 11950 |  11950 |   131M|  9952K|   97M (1)|      94M|
|*  2 |   TABLE ACCESS FULL| ORD      |      1 |    500K|    500K|00:00:00.29 |   22422 |     0 |      0 |       |       |          |         |
|   3 |   TABLE ACCESS FULL| ORD_ITEM |      1 |   2472K|   2472K|00:00:00.61 |   55265 |     0 |      0 |       |       |          |         |
-------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("I"."ORD_NO"="O"."ORD_NO")
   2 - filter(("O"."ORD_DT">='20130101' AND "O"."ORD_DT"<='20131231'))

문제 ​

  1. build는 작은 쪽(2013년 주문)으로 맞게 잡혔다. 그런데도 1번 줄이 onepass로 TEMP를 쓰는 이유를 build에 올라가는 것으로 설명하시오.
  2. 요구한 여섯 칸만 내도록 SQL을 고치고, 고친 뒤의 메모리와 시간을 어림하시오. PGA를 늘리자는 제안에 대한 의견도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자