Skip to content
튜닝 연습인덱스 스캔 효율과 테이블 액세스
ACC-042

테이블 하나만 읽는 SQL의 실행계획에 뷰와 해시 조인이 나온다며 FULL 힌트로 막자고 한다

기초SELECT한빛유통117 / 700

상황 ​

정산팀의 「일별 결제 대기 건수」는 달을 고르면 PENDING 주문이 있는 날짜와 건수를 보여 준다. 하루 수십 번 연다. 실행계획을 본 조민우가 이렇게 말했다. "FROM에는 T_ORD_BIG 하나뿐인데 VIEW와 HASH JOIN이 보인다. 통계가 꼬인 것 같으니 FULL 힌트로 고정하자." 아래는 2024년 11월을 골랐을 때다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · 2024년 11월 27,390건 · 그중 PENDING 2,190건(6일) · PENDING 전체 80,000건
  • 인덱스 IX_ORD_BIG_DT (ORD_DT): BLEVEL 2 · 리프 2,653블록 · CLUSTERING_FACTOR 약 1,000,000
  • 인덱스 IX_ORD_BIG_ST (ORD_ST): BLEVEL 2 · 리프 2,775블록 · CLUSTERING_FACTOR 17,478 · ORD_ST에 히스토그램
  • 두 인덱스 모두 2018년에 만든 단일 컬럼 인덱스다 · 통계 최신 · 다른 인덱스 없음
  • 다음 달부터 화면에 대기 금액 합계(SUM(ORD_AMT))도 보여 달라는 요청이 와 있다

원본 SQL ​

sql
SELECT ORD_DT, COUNT(*) AS pend_cnt
  FROM T_ORD_BIG
 WHERE ORD_ST = 'PENDING'
   AND ORD_DT >= TO_DATE(:v_from, 'YYYYMMDD')
   AND ORD_DT <  TO_DATE(:v_to, 'YYYYMMDD') + 1
 GROUP BY ORD_DT
 ORDER BY ORD_DT

실행계획 학습용 예시 · 건수는 적재 스크립트 그대로 · 인덱스 규모는 교재 02화와 IDX-005 ​

xplan
------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |      1 |        |      6 |00:00:00.02 |     302 |          |
|   1 |  SORT GROUP BY        |                  |      1 |     30 |      6 |00:00:00.02 |     302 | 2048  (0)|
|*  2 |   FILTER              |                  |      1 |        |   2190 |00:00:00.02 |     302 |          |
|*  3 |    VIEW               | index$_join$_001 |      1 |   2191 |   2190 |00:00:00.02 |     302 |          |
|*  4 |     HASH JOIN         |                  |      1 |        |   2190 |00:00:00.02 |     302 | 1624K (0)|
|*  5 |      INDEX RANGE SCAN | IX_ORD_BIG_DT    |      1 |  27390 |  27390 |00:00:00.01 |      76 |          |
|*  6 |      INDEX RANGE SCAN | IX_ORD_BIG_ST    |      1 |  80000 |  80000 |00:00:00.01 |     226 |          |
------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_DATE(:V_TO,'YYYYMMDD')+1>TO_DATE(:V_FROM,'YYYYMMDD'))
   3 - filter(("ORD_ST"='PENDING' AND "ORD_DT">=TO_DATE(:V_FROM,'YYYYMMDD') AND
              "ORD_DT"<TO_DATE(:V_TO,'YYYYMMDD')+1))
   4 - access(ROWID=ROWID)
   5 - access("ORD_DT">=TO_DATE(:V_FROM,'YYYYMMDD') AND "ORD_DT"<TO_DATE(:V_TO,'YYYYMMDD')+1)
   6 - access("ORD_ST"='PENDING')

[참고 — 같은 조건 FULL 강제] 5,826

문제 ​

  1. 3번 ~ 6번 줄이 무엇을 하는지 설명하시오. FROM에 테이블이 하나뿐인데 VIEW와 HASH JOIN이 나온 이유도 설명하시오.
  2. 조민우의 제안(FULL 힌트)을 받아들일지 숫자로 판단하시오.
  3. 다음 달 요청대로 SELECT에 SUM(ORD_AMT)를 더하면 실행계획이 어떻게 바뀔지 예상하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자