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

프리미엄셰이크 세 가지의 한 달 판매 집계가 같은 한 달치 주문상품을 세 번 읽는다

실전SELECT버거167 / 700

상황 ​

마케팅팀이 2013년 7월 프리미엄셰이크 프로모션 성과를 보는 대시보드를 만들었다. 상품명이 프리미엄으로 시작하는 상품 3개의 일별 판매 수량을 내며, 지금은 10분마다 돈다(하루 144번). 점주 앱에도 같은 칸을 넣자는 이야기가 나와 있어서, 그렇게 되면 하루 2만 번쯤 호출된다. 개발자는 "날짜 인덱스를 태워야 빠르다"라며 힌트를 달았다. 오과장은 인덱스를 새로 만들지, SQL만 고칠지 비교한 의견서를 내라고 했다.

테이블과 인덱스 ​

  • ITEM 상품: 92행 · 5블록 · ITEM_PK (ITEM_ID) · 프리미엄셰이크 3개 (ITEM_ID 71, 72, 73)
  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS) · 날짜순 적재
  • 2013년 7월 주문상품 105,012줄이 약 2,350블록에 모여 있다 (ORD_ITEM_X01 리프 약 375블록) · 92개 상품이 고르게 팔려 프리미엄셰이크 3개의 7월 판매는 3,418줄이다
  • POS가 주문상품을 실시간으로 넣는다 (하루 약 3,400줄, 점심과 저녁에 몰린다) · 통계 최신

원본 SQL ​

sql
SELECT /*+ LEADING(t i) USE_NL(i) INDEX(i ORD_ITEM_X01) */
       i.ORD_DT, t.ITEM_NM, SUM(i.ORD_ITEM_QTY) AS qty
  FROM ITEM t, ORD_ITEM i
 WHERE t.ITEM_NM LIKE '프리미엄%'
   AND i.ITEM_ID = t.ITEM_ID
   AND i.ORD_DT BETWEEN :v_from AND :v_to
 GROUP BY i.ORD_DT, t.ITEM_NM
 ORDER BY i.ORD_DT, t.ITEM_NM

실행계획 학습용 예시 ​

xplan
----------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |              |      1 |        |     93 |00:00:00.21 |    8189 |
|   1 |  SORT GROUP BY                  |              |      1 |     93 |     93 |00:00:00.21 |    8189 |
|*  2 |   FILTER                        |              |      1 |        |   3418 |00:00:00.21 |    8189 |
|   3 |    NESTED LOOPS                 |              |      1 |   3424 |   3418 |00:00:00.21 |    8189 |
|*  4 |     TABLE ACCESS FULL           | ITEM         |      1 |      3 |      3 |00:00:00.01 |       5 |
|*  5 |     TABLE ACCESS BY INDEX ROWID | ORD_ITEM     |      3 |   1141 |   3418 |00:00:00.20 |    8184 |
|*  6 |      INDEX RANGE SCAN           | ORD_ITEM_X01 |      3 |   105K |   315K |00:00:00.05 |    1134 |
----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(:V_FROM<=:V_TO)
   4 - filter("T"."ITEM_NM" LIKE '프리미엄%')
   5 - filter("I"."ITEM_ID"="T"."ITEM_ID")
   6 - access("I"."ORD_DT">=:V_FROM AND "I"."ORD_DT"<=:V_TO)

문제 ​

  1. 5번과 6번 줄의 Starts와 A-Rows로 이 SQL의 일량이 어디서 나오는지 설명하시오.
  2. 해시 조인으로 바꾸는 안(가), ORD_ITEM (ITEM_ID, ORD_DT) 인덱스를 만드는 안(나), ORD_ITEM (ITEM_ID, ORD_DT, ORD_ITEM_QTY) 인덱스를 만드는 안(다)을 예상 Buffers로 비교하시오.
  3. 지금(하루 144번)과 점주 앱에 들어갈 때(하루 2만 번)를 나눠 어느 안을 고를지 정하고, 그 안의 부작용까지 서술하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자