Skip to content
튜닝 연습옵티마이저와 통계
OPT-029

BI 도구를 바꾼 뒤로 월 상품 판매 리포트가 판매 2만 건마다 판매상품을 찾아간다

중급SELECT유통619 / 700

상황 ​

본사는 올해 BI 도구를 바꾸면서 날짜 조건을 모두 달력 차원(CF_CAL)으로 거르게 의미 계층을 새로 만들었다. 사용자가 「연월」을 고르면 BI가 달력 테이블을 조인하고 YM 조건을 리터럴로 거는 SQL을 만든다. 옛 도구에서 0.06초였던 「월 상품 판매」 리포트가 0.3초씩 걸린다. MD 20명이 하루 수백 번 연다. 아래는 2023년 6월을 골랐을 때다. BI 관리자는 리포트마다 SQL을 직접 고쳐 넣을 수 있다.

테이블과 인덱스 ​

  • CF_CAL 달력(이 문제용 · BI 날짜 차원): 1950-01-01 ~ 2049-12-31 36,525행 · 176블록 · YMD VARCHAR2(8) PK(NUM_DISTINCT 36,525) · YM VARCHAR2(6)(NUM_DISTINCT 1,200) · DOW_NM · HOLI_YN
  • CF10 판매: 500,000행 · 4,583블록 · SLE_DT VARCHAR2(8) '20220101' ~ '20231231'(NUM_DISTINCT 730, 판매가 없는 날은 없다) · 날짜순 적재 · 2023년 6월 20,953건 · IX_CF10_SLE_DT (SLE_DT): BLEVEL 2 · 리프 1,393 · CF 9,921
  • CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO): BLEVEL 2 · 판매 한 건에 평균 2.19줄 · 2023년 6월 판매상품 45,957줄
  • 통계 최신 · 히스토그램 없음

원본 SQL ​

sql
SELECT s.ITM_NO, SUM(s.SLE_QTY) AS qty, SUM(s.SLE_QTY * s.SLE_UPRC) AS amt
  FROM CF_CAL c, CF10 h, CF11 s
 WHERE c.YM = '202306'
   AND h.SLE_DT = c.YMD
   AND s.SLE_NO = h.SLE_NO
 GROUP BY s.ITM_NO

실행계획 학습용 예시 · 판매일자 범위의 추정 5,177은 교재 10화 측정 ​

xplan
Plan hash value: 2504718839

------------------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |                |      1 |        |     88 |00:00:00.31 |   63575 |
|   1 |  HASH GROUP BY                         |                |      1 |     88 |     88 |00:00:00.31 |   63575 |
|   2 |   NESTED LOOPS                         |                |      1 |    913 |  45957 |00:00:00.30 |   63575 |
|   3 |    NESTED LOOPS                        |                |      1 |    913 |  45957 |00:00:00.21 |   42622 |
|   4 |     NESTED LOOPS                       |                |      1 |    417 |  20953 |00:00:00.02 |     716 |
|*  5 |      TABLE ACCESS FULL                 | CF_CAL         |      1 |     30 |     30 |00:00:00.01 |     176 |
|   6 |      TABLE ACCESS BY INDEX ROWID BATCHED| CF10          |     30 |    685 |  20953 |00:00:00.02 |     540 |
|*  7 |       INDEX RANGE SCAN                 | IX_CF10_SLE_DT |     30 |    685 |  20953 |00:00:00.01 |     120 |
|*  8 |     INDEX RANGE SCAN                   | CF11_PK        |  20953 |      2 |  45957 |00:00:00.12 |   41906 |
|   9 |    TABLE ACCESS BY INDEX ROWID         | CF11           |  45957 |      1 |  45957 |00:00:00.07 |   20953 |
------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   5 - filter("C"."YM"='202306')
   7 - access("H"."SLE_DT"="C"."YMD")
   8 - access("S"."SLE_NO"="H"."SLE_NO")

문제 ​

  1. 4번 줄의 E-Rows 417을 손으로 계산하시오. 6번 줄은 날짜 하나에 685건으로 맞게 보는데 4번 줄이 그 30배가 아니라 417인 이유를 설명하고, 그 숫자 때문에 무엇을 골랐는지 쓰시오.
  2. 결과가 바뀌지 않게 SQL을 고쳐 추정을 바로잡으시오. 달력 쪽을 고치는 방법, 동적 샘플링, 힌트와도 비교해 각각의 대가를 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자