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

히스토그램 칸을 다섯 개로 줄인 뒤 2,000원 균일가와 12,000원 세트 분석만 느려졌다

중급PLSQL유통610 / 700

상황 ​

본사 MD팀의 「단가대별 매장 판매」는 단가를 하나 고르면 그 단가로 팔린 판매상품 줄을 매장별로 센다(단가는 화면이 리터럴로 넣는다). MD 20명이 하루 수백 번 누른다. 6월에 유통지원팀 DBA가 판매상품 테이블의 통계 수집을 가볍게 하겠다며 단가 히스토그램의 칸을 다섯 개로 줄였다. 스크립트 주석에는 "단가는 많이 팔리는 다섯 개만 알면 된다"라고 적혀 있다. 그 뒤로 2,500원이나 3,000원은 그대로인데, 2,000원 균일가 상품과 12,000원 선물 세트를 고를 때만 0.06초에서 0.25초로 느려졌다.

테이블과 인덱스 ​

  • CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · SLE_UPRC 단가 11종(상품마다 단가가 하나다)
  • 단가 분포: 2,500원 533,248 · 3,000원 241,587 · 3,500원 187,601 · 4,500원 24,478 · 8,000원 22,081 · 12,000원 18,789(가장 비싼 값) · 5,000원 15,818 · 4,000원 15,493 · 7,000원 12,631 · 2,000원 12,556(가장 싼 값) · 10,000원 12,426
  • 지금 통계: SLE_UPRC NUM_DISTINCT 11 · HISTOGRAM TOP-FREQUENCY · NUM_BUCKETS 5 · 선호도 FOR ALL COLUMNS SIZE 1 FOR COLUMNS SIZE 5 SLE_UPRC
  • CF10 판매: 500,000행 · 4,583블록 · CF10_PK (SLE_NO): BLEVEL 2

원본 SQL ​

sql
-- 6월 · 유통지원팀 DBA : CF11 통계 수집을 가볍게 ("단가는 많이 팔리는 다섯 개만 알면 된다")
BEGIN
  DBMS_STATS.SET_TABLE_PREFS('PUP', 'CF11', 'METHOD_OPT',
                             'FOR ALL COLUMNS SIZE 1 FOR COLUMNS SIZE 5 SLE_UPRC');
  DBMS_STATS.GATHER_TABLE_STATS('PUP', 'CF11');
END;
/

-- (참고) 「단가대별 매장 판매」 : SQL 은 고치지 않는다
SELECT h.SHP_NO, COUNT(*) AS line_cnt, SUM(s.SLE_QTY) AS qty
  FROM CF11 s, CF10 h
 WHERE s.SLE_UPRC = 2000
   AND h.SLE_NO = s.SLE_NO
 GROUP BY h.SHP_NO;

실행계획 학습용 예시 · 단가 분포와 TOP-FREQUENCY 끝점은 교재 10화 복사본 측정 ​

xplan
[USER_TAB_HISTOGRAMS · CF11.SLE_UPRC (SIZE 5)]
 ENDPOINT_NUMBER   ENDPOINT_VALUE
               1             2000
         533,249             2500
         774,836             3000
         962,437             3500
         962,438            12000

[「단가대별 매장 판매」 · SLE_UPRC = 2000]
-----------------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |      1 |        |      5 |00:00:00.25 |   45872 |
|   1 |  HASH GROUP BY               |         |      1 |      1 |      5 |00:00:00.25 |   45872 |
|   2 |   NESTED LOOPS               |         |      1 |      1 |  12556 |00:00:00.24 |   45872 |
|   3 |    NESTED LOOPS              |         |      1 |      1 |  12556 |00:00:00.19 |   33316 |
|*  4 |     TABLE ACCESS FULL        | CF11    |      1 |      1 |  12556 |00:00:00.11 |    8204 |
|*  5 |     INDEX UNIQUE SCAN        | CF10_PK |  12556 |      1 |  12556 |00:00:00.06 |   25112 |
|   6 |    TABLE ACCESS BY INDEX ROWID| CF10   |  12556 |      1 |  12556 |00:00:00.04 |   12556 |
-----------------------------------------------------------------------------------------------
   4 - filter("S"."SLE_UPRC"=2000)
   5 - access("H"."SLE_NO"="S"."SLE_NO")

[같은 SQL · SLE_UPRC = 2500]   E-Rows 533K · HASH JOIN · Buffers 12,787 · 0.06초
[같은 SQL · SLE_UPRC = 12000]  E-Rows 1 · NESTED LOOPS · Buffers 61,6xx · 0.31초

문제 ​

  1. 2,000원과 12,000원에서만 4번 줄의 E-Rows가 1이 된 이유를 히스토그램 끝점으로 설명하고, 그 1 때문에 무엇을 골랐는지 쓰시오.
  2. SQL은 그대로 두고 통계 설정을 고치시오. 칸을 다섯 개로 줄여서 얻은 것이 있는지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자