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

힌트를 USE_HASH로 일괄 바꾼 뒤 '최근 주문 50줄' 상황판이 3초씩 걸린다

중급SELECT버거164 / 700

상황 ​

본사 상황실의 「최근 주문」 상황판은 전 매장의 가장 최근 주문 상품 50줄을 보여 주고 10초마다 새로 고친다(하루 8,640번). 지난달 외부 컨설턴트가 집계 배치를 빠르게 하려고 주문 모듈 SQL의 USE_NL을 USE_HASH로 일괄 바꿨고, 이 상황판 SQL도 함께 바뀌었다. 그 뒤로 상황판이 한 번에 3초씩 걸리고 서버 CPU 사용률이 올랐다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_PK (ORD_NO) · ORD_X01 (ORD_DT, ORD_HMS) · 날짜순 적재
  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · 주문당 평균 2.47줄
  • ITEM 상품: 92행 · 5블록 · ITEM_PK (ITEM_ID)
  • pga_aggregate_target 512M · 통계 최신

원본 SQL ​

sql
SELECT *
  FROM (SELECT /*+ LEADING(o i t) USE_HASH(i t) */
               o.ORD_DT, o.ORD_HMS, o.SHOP_NO, o.ORD_NO,
               t.ITEM_NM, i.ORD_ITEM_QTY
          FROM ORD o, ORD_ITEM i, ITEM t
         WHERE i.ORD_NO  = o.ORD_NO
           AND t.ITEM_ID = i.ITEM_ID
         ORDER BY o.ORD_DT DESC, o.ORD_HMS DESC)
 WHERE ROWNUM <= 50

실행계획 학습용 예시 ​

xplan
-----------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  Used-Mem |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |          |      1 |        |     50 |00:00:03.06 |   77692 |           |
|*  1 |  COUNT STOPKEY           |          |      1 |        |     50 |00:00:03.06 |   77692 |           |
|   2 |   VIEW                   |          |      1 |  2472K |     50 |00:00:03.06 |   77692 |           |
|*  3 |    SORT ORDER BY STOPKEY |          |      1 |  2472K |     50 |00:00:03.06 |   77692 |   18K (0) |
|*  4 |     HASH JOIN            |          |      1 |  2472K |  2472K |00:00:02.41 |   77692 | 1036K (0) |
|   5 |      TABLE ACCESS FULL   | ITEM     |      1 |     92 |     92 |00:00:00.01 |       5 |           |
|*  6 |      HASH JOIN           |          |      1 |  2472K |  2472K |00:00:01.88 |   77687 |   47M (0) |
|   7 |       TABLE ACCESS FULL  | ORD      |      1 |  1000K |  1000K |00:00:00.29 |   22422 |           |
|   8 |       TABLE ACCESS FULL  | ORD_ITEM |      1 |  2472K |  2472K |00:00:00.61 |   55265 |           |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(ROWNUM<=50)
   3 - filter(ROWNUM<=50)
   4 - access("T"."ITEM_ID"="I"."ITEM_ID")
   6 - access("I"."ORD_NO"="O"."ORD_NO")

문제 ​

  1. 이 SQL이 50줄을 내려고 몇 행을 조인하고 정렬하는지 A-Rows와 Buffers로 설명하고, 해시 조인에서는 왜 50줄에서 멈출 수 없는지 서술하시오.
  2. 50줄을 읽으면 멈추도록 SQL을 고치고, 이 방식이 성립하는 조건을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자