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

상품 인덱스를 만들고 힌트까지 넣었는데 상품 실적 조회가 FULL과 똑같이 896블록을 읽는다

중급SELECT한빛유통98 / 700

상황 ​

상품팀의 「상품별 판매 실적」은 상품 하나를 고르면 지금까지 팔린 줄 수와 수량, 금액을 보여 준다. MD 열 명이 하루 수백 번 연다. 지난주 조민우가 이 화면을 위해 IX_T_ORD_DET_ITM (ITM_ID)를 만들었다. 옵티마이저가 그 인덱스를 쓰지 않자 INDEX 힌트를 넣었는데, 힌트를 넣으나 빼나 Buffers는 900 안팎이다. 조민우는 "인덱스가 깨진 것 같으니 REBUILD를 해 보겠다"고 한다. 아래는 상품 ITM00037이다.

테이블과 인덱스 ​

  • T_ORD_DET: 200,000행 · 896블록(블록당 약 223행) · (ORD_SEQ, ORD_DET_NO) 순으로 쌓였다 · PK_T_ORD_DET (ORD_SEQ, ORD_DET_NO)
  • ITM_ID 100종, 상품마다 2,000줄 · 상품 번호는 (ORD_SEQ + ORD_DET_NO)를 100으로 나눈 나머지로 매겨져, 쌓인 순서로 보면 약 100줄마다 같은 상품이 돌아온다
  • 인덱스 IX_T_ORD_DET_ITM (ITM_ID): BLEVEL 1 · 리프 약 600블록 · CLUSTERING_FACTOR 89,600 · 이 화면만 쓴다 · 통계 최신

원본 SQL ​

sql
SELECT /*+ INDEX(d IX_T_ORD_DET_ITM) */
       COUNT(*) AS line_cnt, SUM(d.ORD_QTY) AS qty, SUM(d.ORD_QTY * d.UNT_PRC) AS amt
  FROM T_ORD_DET d
 WHERE d.ITM_ID = :v_itm

실행계획 학습용 예시 · 건수는 적재 스크립트 그대로 ​

xplan
[힌트를 넣은 지금]
------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name             | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                  |      1 |        |      1 |00:00:00.01 |     903 |
|   1 |  SORT AGGREGATE                      |                  |      1 |      1 |      1 |00:00:00.01 |     903 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| T_ORD_DET        |      1 |   2000 |   2000 |00:00:00.01 |     903 |
|*  3 |    INDEX RANGE SCAN                  | IX_T_ORD_DET_ITM |      1 |   2000 |   2000 |00:00:00.01 |       7 |
------------------------------------------------------------------------------------------------------------------
   3 - access("D"."ITM_ID"=:V_ITM)

[힌트 없이: 옵티마이저가 고른 계획]
------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name             | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                  |      1 |        |      1 |00:00:00.01 |     896 |
|   1 |  SORT AGGREGATE                      |                  |      1 |      1 |      1 |00:00:00.01 |     896 |
|*  2 |   TABLE ACCESS FULL                  | T_ORD_DET        |      1 |   2000 |   2000 |00:00:00.01 |     896 |
------------------------------------------------------------------------------------------------------------------
   2 - filter("D"."ITM_ID"=:V_ITM)

문제 ​

  1. 상품 하나의 2,000줄(전체의 1%)을 인덱스로 찾았는데 테이블을 896블록이나 읽은 이유를, CLUSTERING_FACTOR와 상품 번호가 매겨진 규칙으로 설명하시오. 옵티마이저가 힌트 없이는 이 인덱스를 고르지 않은 이유도 설명하시오.
  2. 이 화면이 테이블을 읽지 않도록 SQL과 인덱스를 고치시오. REBUILD 제안을 어떻게 판단하는지와 고친 안의 대가도 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자