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

키오스크가 메뉴판 한 장을 띄울 때마다 가격 이력 5천 블록을 읽는다

기초SELECT버거197 / 700

상황 ​

매장 키오스크는 화면이 켜질 때와 주문이 끝날 때마다 판매 중인 메뉴의 오늘 가격을 다시 읽는다. 매장 200곳의 키오스크가 하루 3만 번쯤 호출한다. 본사는 주간 행사가를 운영하려고 2012년부터 매주 월요일에 전 메뉴의 그 주 가격을 한 줄씩 올린다(값이 같아도 올린다). 개발자는 "가격표가 겨우 92줄인데 왜 무거운지 모르겠다"라고 한다. 아래는 2013-12-31(화요일)에 뜬 실행계획이다.

테이블과 인덱스 ​

  • ITEM 상품: 92행 · 5블록 · ITEM_PK (ITEM_ID) · 판매 중(SALE_YN = 'Y') 84개
  • ITEM_PRC_HIS 메뉴 가격 이력 (이 문제에서 쓰는 파생 테이블, 선분이력): ITEM_ID · STA_DT · END_DT (둘 다 VARCHAR2(8)) · SALE_PRC · 9,568행(92개 × 104주) · 60블록
  • 지난 구간의 END_DT는 그 주 일요일이고, 지금 구간의 END_DT는 '99991231'이다 · 구간은 겹치거나 끊기지 않는다 · 아직 다음 주 가격을 미리 올리는 기능은 없다
  • 인덱스는 ITEM_PRC_HIS_PK (ITEM_ID, STA_DT)뿐이다 · BLEVEL 1 · 리프 약 30블록 · 주마다 92행씩 쌓여서 메뉴 하나의 104행은 약 60블록에 흩어져 있다 · 통계 최신

원본 SQL ​

sql
SELECT t.ITEM_ID, t.ITEM_NM, h.SALE_PRC
  FROM ITEM t, ITEM_PRC_HIS h
 WHERE t.SALE_YN = 'Y'
   AND h.ITEM_ID = t.ITEM_ID
   AND :v_today BETWEEN h.STA_DT AND h.END_DT
 ORDER BY t.ITEM_ID

실행계획 학습용 예시 ​

xplan
--------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                 |      1 |        |     84 |00:00:00.02 |    5213 |
|   1 |  SORT ORDER BY                |                 |      1 |     84 |     84 |00:00:00.02 |    5213 |
|   2 |   NESTED LOOPS                |                 |      1 |     84 |     84 |00:00:00.02 |    5213 |
|   3 |    NESTED LOOPS               |                 |      1 |   4368 |   8736 |00:00:00.01 |     173 |
|*  4 |     TABLE ACCESS FULL         | ITEM            |      1 |     84 |     84 |00:00:00.01 |       5 |
|*  5 |     INDEX RANGE SCAN          | ITEM_PRC_HIS_PK |     84 |     52 |   8736 |00:00:00.01 |     168 |
|*  6 |    TABLE ACCESS BY INDEX ROWID| ITEM_PRC_HIS    |   8736 |      1 |     84 |00:00:00.01 |    5040 |
--------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   4 - filter("T"."SALE_YN"='Y')
   5 - access("H"."ITEM_ID"="T"."ITEM_ID" AND "H"."STA_DT"<=:V_TODAY)
   6 - filter("H"."END_DT">=:V_TODAY)

문제 ​

  1. 메뉴 84개의 가격을 얻는 데 5,213블록을 읽은 까닭을 5번과 6번 줄의 A-Rows와 Predicate Information으로 설명하시오.
  2. 오늘 가격을 메뉴마다 한 줄만 읽어 찾도록 SQL과 인덱스를 고치시오. 나중에 다음 주 가격을 미리 올리는 기능이 생기면 고친 SQL이 어떻게 되는지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자