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

시험 주문 한 건을 되살린 뒤 금액대별 등급 매출이 어느 구간이든 고객 테이블을 20만 번 읽는다

중급SELECT한빛유통617 / 700

상황 ​

영업기획팀의 「금액대별 등급 매출」은 금액 구간을 고르면 그 구간 주문을 고객 등급별로 묶는다. 구간은 10만 원 단위이고 화면이 리터럴로 넣는다. 지난주부터 어느 구간을 골라도 느리다는 말이 나왔다. 조민우가 보니 지난 일요일에 통계가 다시 모였고, 그 전 주에 감사팀 요청으로 2019년 부하 시험 주문 한 건을 백업에서 되살려 T_ORD_BIG에 넣었다. 주문 금액이 9,999,999,999원이다. 감사가 끝날 때까지 지우지 말라는 요청이 붙어 있다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,001행 · 5,826블록 · ORD_AMT 10,000 ~ 500,000원(100원 단위, 고르게) + 시험 주문 1건 9,999,999,999원 · 이 SQL에 쓰이는 인덱스는 없다
  • 통계: 지난 일요일 수집 · ORD_AMT NUM_DISTINCT 4,902 · 최솟값 10,000 · 최댓값 9,999,999,999 · 히스토그램 없음 · 선호도 FOR ALL COLUMNS SIZE 1 FOR COLUMNS SIZE 254 ORD_ST(정책서 1호)
  • 10만 원 이상 20만 원 미만 주문 204,082건(구간마다 약 20만 건)
  • M_CUS: 2,000행 · 30블록 · PK_M_CUS (CUS_ID) · CUS_GD A · B · C

원본 SQL ​

sql
SELECT c.CUS_GD, COUNT(*) AS cnt, ROUND(AVG(o.ORD_AMT)) AS avg_amt
  FROM T_ORD_BIG o, M_CUS c
 WHERE o.ORD_AMT >= 100000
   AND o.ORD_AMT <  200000
   AND c.CUS_ID = o.CUS_ID
 GROUP BY c.CUS_GD

실행계획 학습용 예시 ​

xplan
---------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |      1 |        |      3 |00:00:00.18 |    214K |
|   1 |  HASH GROUP BY               |           |      1 |      3 |      3 |00:00:00.18 |    214K |
|   2 |   NESTED LOOPS               |           |      1 |    214 |    204K|00:00:00.17 |    214K |
|   3 |    NESTED LOOPS              |           |      1 |    214 |    204K|00:00:00.09 |   10112 |
|*  4 |     TABLE ACCESS FULL        | T_ORD_BIG |      1 |    214 |    204K|00:00:00.05 |    5826 |
|*  5 |     INDEX UNIQUE SCAN        | PK_M_CUS  |    204K|      1 |    204K|00:00:00.03 |    4286 |
|   6 |    TABLE ACCESS BY INDEX ROWID| M_CUS    |    204K|      1 |    204K|00:00:00.06 |    204K |
---------------------------------------------------------------------------------------------
   4 - filter(("O"."ORD_AMT">=100000 AND "O"."ORD_AMT"<200000))
   5 - access("C"."CUS_ID"="O"."CUS_ID")

[USER_TAB_COL_STATISTICS · ORD_AMT]  NUM_DISTINCT 4,902 · LOW 10000 · HIGH 9999999999 · HISTOGRAM NONE

문제 ​

  1. 4번 줄의 E-Rows 214를 손으로 계산하고, 시험 주문 한 건이 어느 구간에서나 추정을 망가뜨린 이유를 설명하시오.
  2. 시험 주문을 지울 수 없다는 조건에서 SQL은 그대로 두고 통계로 고치시오. 감사가 끝난 뒤의 처리도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자