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

판매 마트의 리포트 세 개가 모두 팩트를 통째로 읽는데, 업체는 리포트마다 결합 인덱스를 하나씩 만들자고 한다

실전DDL유통220 / 700

상황 ​

본사가 BI 도구를 들이면서 판매와 판매상품을 합친 판매 마트 DW_SLE_ITM을 만들었다. 첫 리포트 세 개가 붙었는데 셋 다 팩트를 FULL로 읽는다. 구축 업체는 R1과 R2에 맞춘 결합 인덱스를 하나씩 만들자고 제안했다. 박팀장은 "BI 사용자는 조건을 계속 바꿀 텐데, 리포트가 늘 때마다 인덱스를 만들 거냐"며 대안을 비교해 오라고 했다. 마트는 매일 밤 02:00 배치가 전날 판매 약 1,500줄을 한 세션에서 덧붙이고, 낮에는 읽기만 한다. 호출 빈도는 R1이 하루 400번(거래처 담당 MD), R2가 30번(점장 회의), R3가 50번(경영진 대시보드)이다.

테이블과 인덱스 ​

  • DW_SLE_ITM 판매 팩트: 1,096,708행 · 8,860블록 · SLE_DT · SHP_NO · ITM_NO · SLE_NO · SLE_QTY · SLE_AMT · 날짜순으로 쌓인다 · 인덱스 없음(적재가 느려진다며 만들지 않았다)
  • 차원: W_DAY 날짜 730행 · 6블록(DT · YM · DOW_CD) / CF01 상품 109행 · 5블록(PTNR_NO 거래처 15곳 · CTG_NO) / CF02 카테고리 18행 · 4블록(UP_CTG_NO 상위 분류) / CF07 매장 6행 · 4블록
  • R1: 거래처 P07의 상품 8개가 판매 줄의 7.3% · 2023년 12월이 46,322줄(4.2%) · 둘을 겹치면 3,358줄(0.3%)
  • R2: 매장 1001과 1002가 38% · 2023년 주말이 15% · 음료 상위 분류(상품 26개)가 24% · 셋을 겹치면 15,037줄(1.4%)
  • R3: 조건 없이 2년 전체를 날짜별로 묶는다
  • 통계 최신 · STAR_TRANSFORMATION_ENABLED = FALSE

원본 SQL ​

sql
-- [R1] 거래처 월 매출 (하루 400번)
SELECT p.ITM_NO, p.ITM_NM, SUM(f.SLE_QTY) AS qty, SUM(f.SLE_AMT) AS amt
  FROM DW_SLE_ITM f, CF01 p, W_DAY d
 WHERE p.PTNR_NO = :v_ptnr
   AND d.YM      = :v_ym
   AND f.ITM_NO  = p.ITM_NO
   AND f.SLE_DT  = d.DT
 GROUP BY p.ITM_NO, p.ITM_NM;

-- [R2] 매장 · 요일 · 분류 판매 (하루 30번)
SELECT f.SHP_NO, d.DOW_CD, g.CTG_NM, SUM(f.SLE_AMT) AS amt
  FROM DW_SLE_ITM f, W_DAY d, CF01 p, CF02 g
 WHERE f.SHP_NO IN (:v_shp1, :v_shp2)
   AND d.YM BETWEEN :v_ym_from AND :v_ym_to
   AND d.DOW_CD IN ('1', '7')
   AND g.UP_CTG_NO = :v_up_ctg
   AND p.CTG_NO = g.CTG_NO
   AND f.ITM_NO = p.ITM_NO
   AND f.SLE_DT = d.DT
 GROUP BY f.SHP_NO, d.DOW_CD, g.CTG_NM;

-- [R3] 일별 매출 추이 (하루 50번)
SELECT f.SLE_DT, SUM(f.SLE_AMT) AS amt
  FROM DW_SLE_ITM f
 GROUP BY f.SLE_DT
 ORDER BY f.SLE_DT;

실행계획 학습용 예시 ​

xplan
[R1] 거래처 P07 · 2023년 12월
-----------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  Used-Mem |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |            |      1 |        |      8 |00:00:00.31 |    8871 |           |
|   1 |  HASH GROUP BY         |            |      1 |      7 |      8 |00:00:00.31 |    8871 | 1022K (0) |
|*  2 |   HASH JOIN            |            |      1 |   3104 |   3358 |00:00:00.31 |    8871 | 1156K (0) |
|*  3 |    TABLE ACCESS FULL   | CF01       |      1 |      7 |      8 |00:00:00.01 |       5 |           |
|*  4 |    HASH JOIN           |            |      1 |  45057 |  46322 |00:00:00.27 |    8866 | 1286K (0) |
|*  5 |     TABLE ACCESS FULL  | W_DAY      |      1 |     30 |     31 |00:00:00.01 |       6 |           |
|   6 |     TABLE ACCESS FULL  | DW_SLE_ITM |      1 |  1096K |  1096K |00:00:00.09 |    8860 |           |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("F"."ITM_NO"="P"."ITM_NO")
   3 - filter("P"."PTNR_NO"=:V_PTNR)
   4 - access("F"."SLE_DT"="D"."DT")
   5 - filter("D"."YM"=:V_YM)

[R2] 매장 1001과 1002 · 2023년 주말 · 음료 상위 분류
-----------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  Used-Mem |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |            |      1 |        |     12 |00:00:00.34 |    8875 |           |
|   1 |  HASH GROUP BY         |            |      1 |     12 |     12 |00:00:00.34 |    8875 | 1022K (0) |
|*  2 |   HASH JOIN            |            |      1 |  14382 |  15037 |00:00:00.34 |    8875 | 1290K (0) |
|*  3 |    HASH JOIN           |            |      1 |     26 |     26 |00:00:00.01 |       9 | 1156K (0) |
|*  4 |     TABLE ACCESS FULL  | CF02       |      1 |      3 |      3 |00:00:00.01 |       4 |           |
|   5 |     TABLE ACCESS FULL  | CF01       |      1 |    109 |    109 |00:00:00.01 |       5 |           |
|*  6 |    HASH JOIN           |            |      1 |  59200 |  62580 |00:00:00.30 |    8866 | 1286K (0) |
|*  7 |     TABLE ACCESS FULL  | W_DAY      |      1 |    104 |    104 |00:00:00.01 |       6 |           |
|*  8 |     TABLE ACCESS FULL  | DW_SLE_ITM |      1 |   416K |   416K |00:00:00.12 |    8860 |           |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("F"."ITM_NO"="P"."ITM_NO")
   3 - access("P"."CTG_NO"="G"."CTG_NO")
   4 - filter("G"."UP_CTG_NO"=:V_UP_CTG)
   6 - access("F"."SLE_DT"="D"."DT")
   7 - filter(("D"."YM">=:V_YM_FROM AND "D"."YM"<=:V_YM_TO AND INTERNAL_FUNCTION("D"."DOW_CD")))
   8 - filter(("F"."SHP_NO"=:V_SHP1 OR "F"."SHP_NO"=:V_SHP2))

[R3] 2년 전체 일별 매출
---------------------------------------------------------------------------------------------------------
| Id  | Operation            | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  Used-Mem |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |            |      1 |        |    730 |00:00:00.29 |    8860 |           |
|   1 |  SORT GROUP BY       |            |      1 |    730 |    730 |00:00:00.29 |    8860 | 43008 (0) |
|   2 |   TABLE ACCESS FULL  | DW_SLE_ITM |      1 |  1096K |  1096K |00:00:00.08 |    8860 |           |
---------------------------------------------------------------------------------------------------------

문제 ​

  1. 세 리포트마다 차원 조건을 하나씩 적용했을 때와 모두 적용했을 때 팩트에서 남는 행 수를 쓰고, 지금 계획의 일량을 하루 단위로 계산하시오.
  2. 업체 안(R1용 (ITM_NO, SLE_DT), R2용 (SHP_NO, SLE_DT, ITM_NO) 결합 인덱스)과 팩트의 차원 키마다 단일 컬럼 비트맵 인덱스를 두고 스타 변환을 쓰는 안을 리포트별 예상 블록과 확장성으로 비교하고, 권하는 안을 DDL로 작성하시오.
  3. 권하는 안이 야간 적재와 동시 DML에 주는 영향과 적재 절차를 서술하시오. R3는 어떻게 할지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자