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

정보계의 「분기 상품 매출」 리포트가 상품 25줄을 내는 데 3초 가까이 걸린다

중급SELECT한빛유통218 / 700

상황 ​

한빛유통 정보계에는 운영 DB의 주문과 주문상세를 매일 밤 합쳐 넣는 주문상세 마트가 있다. 구축 업체가 남긴 「리포트 작성 가이드」에는 "스타 조인: 차원부터 읽어 팩트를 결합 인덱스로 찾는다"는 항목과 함께 아래 SQL의 힌트가 템플릿으로 적혀 있다. 지난주 만든 「분기 등급별 상품 매출」(B 등급 고객의 분기 신선 상품 매출)도 이 템플릿을 따랐는데 한 번에 3초 가까이 걸린다. 같은 템플릿으로 만든 「VIP 주간 상품 매출」(A 등급 20명, 일주일, 상품 5개)은 0.01초다. 아래는 2024년 4분기로 조회한 실행계획이다.

테이블과 인덱스 ​

  • DW_ORD_DET 주문상세 마트: 200,000행 · 1,250블록 · ORD_DT(자정) · CUS_ID · ITM_ID · ORD_QTY · SLE_AMT · 2023-01-01 ~ 2024-12-31을 날짜순으로 적재 · IX_DW_ORD_DET_STAR (ORD_DT, CUS_ID, ITM_ID) BLEVEL 2 · 리프 약 910블록
  • 2024년 4분기 25,170행(리프 약 115블록, 테이블 약 157블록에 모여 있다) · 그중 B 등급 고객 2,290행 · 그중 신선 상품 571행
  • D_DATE 날짜: 731행 · 6블록 · DT / D_CUS 고객: 2,000행 · 30블록 · CUS_ID · CUS_GD(B 180명) / D_ITM 상품: 100행 · 5블록 · ITM_ID · ITM_NM · ITM_TP(신선 'FRESH' 25개)
  • 통계 최신

원본 SQL ​

sql
SELECT /*+ LEADING(d c i f) USE_NL(f) INDEX(f IX_DW_ORD_DET_STAR) */   -- 가이드 3.2 스타 조인 템플릿
       i.ITM_ID, i.ITM_NM, SUM(f.ORD_QTY) AS qty, SUM(f.SLE_AMT) AS amt
  FROM D_DATE d, D_CUS c, D_ITM i, DW_ORD_DET f
 WHERE d.DT >= :v_from
   AND d.DT <  :v_to
   AND c.CUS_GD = :v_gd
   AND i.ITM_TP = :v_tp
   AND f.ORD_DT = d.DT
   AND f.CUS_ID = c.CUS_ID
   AND f.ITM_ID = i.ITM_ID
 GROUP BY i.ITM_ID, i.ITM_NM

실행계획 학습용 예시 ​

xplan
----------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name               | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  Used-Mem |
----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                    |      1 |        |     25 |00:00:02.71 |   1243K |           |
|   1 |  HASH GROUP BY                  |                    |      1 |     25 |     25 |00:00:02.71 |   1243K | 1201K (0) |
|   2 |   NESTED LOOPS                  |                    |      1 |    567 |    571 |00:00:02.70 |   1243K |           |
|   3 |    NESTED LOOPS                 |                    |      1 |    567 |    571 |00:00:02.69 |   1242K |           |
|   4 |     MERGE JOIN CARTESIAN        |                    |      1 |   414K |   414K |00:00:00.21 |      41 |           |
|   5 |      MERGE JOIN CARTESIAN       |                    |      1 |  16560 |  16560 |00:00:00.01 |      36 |           |
|*  6 |       TABLE ACCESS FULL         | D_DATE             |      1 |     92 |     92 |00:00:00.01 |       6 |           |
|   7 |       BUFFER SORT               |                    |     92 |    180 |  16560 |00:00:00.01 |      30 | 15360 (0) |
|*  8 |        TABLE ACCESS FULL        | D_CUS              |      1 |    180 |    180 |00:00:00.01 |      30 |           |
|   9 |      BUFFER SORT                |                    |  16560 |     25 |   414K |00:00:00.12 |       5 |  2048 (0) |
|* 10 |       TABLE ACCESS FULL         | D_ITM              |      1 |     25 |     25 |00:00:00.01 |       5 |           |
|* 11 |     INDEX RANGE SCAN            | IX_DW_ORD_DET_STAR |   414K |      1 |    571 |00:00:02.31 |   1242K |           |
|  12 |    TABLE ACCESS BY INDEX ROWID  | DW_ORD_DET         |    571 |      1 |    571 |00:00:00.01 |     571 |           |
----------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   6 - filter(("D"."DT">=:V_FROM AND "D"."DT"<:V_TO))
   8 - filter("C"."CUS_GD"=:V_GD)
  10 - filter("I"."ITM_TP"=:V_TP)
  11 - access("F"."ORD_DT"="D"."DT" AND "F"."CUS_ID"="C"."CUS_ID" AND "F"."ITM_ID"="I"."ITM_ID")

문제 ​

  1. 11번 줄의 Starts가 어디서 나왔는지 4번과 5번 줄로 계산하고, 그중 몇 번이 행을 찾았는지 쓰시오. 같은 템플릿이 「VIP 주간 상품 매출」에서는 빨랐던 이유도 설명하시오.
  2. 이 리포트의 SQL을 고치고, 가이드의 '스타 조인' 항목을 어떻게 고쳐 써야 할지 쓰는 조건과 함께 제안하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자