Skip to content
튜닝 연습파티션
PART-024

2022년 칸의 인덱스를 끄는 스크립트가 오류 없이 끝났는데 인덱스가 한 블록도 줄지 않았다

중급DDL한빛유통399 / 700

상황 ​

오과장은 다음 달 2022년 칸 12개를 압축하기로 했다. 압축으로 칸을 옮겨 쓰면 그 칸의 로컬 인덱스도 다시 만들어야 하는데, 2022년 주문은 거의 조회되지 않으니 그 칸의 인덱스부터 없애겠다고 했다. 그래서 2022년 칸마다 INDEXING OFF를 주는 스크립트를 돌렸다. 스크립트는 오류 없이 끝났지만 인덱스 크기는 그대로다. 박팀장은 제대로 되게 고치되, 이 테이블을 읽는 화면들이 어떻게 되는지까지 정리해 오라고 했다.

테이블과 인덱스 ​

  • T_ORD_BIG_P14 주문(파티션 복사본, 교재 14화): 1,000,000행 · PARTITION BY RANGE (ORD_DT) 월별 36칸(P202201 ~ P202412)과 빈 PMAX, 모두 37칸. 2022년은 1 ~ 12번째 칸이다. 칸 하나를 FULL로 읽으면 약 161블록이다. 2022년 칸에는 DML이 없다.
  • LOCAL 인덱스 IX_P14_CUS_DT (CUS_ID, ORD_DT): 3,240블록(칸마다 약 90블록, 높이 2). LOCAL 인덱스 IX_P14_ST_DT (ORD_ST, ORD_DT): 2,880블록(칸마다 약 80블록). GLOBAL 유니크 인덱스 IX_P14_SEQ (ORD_SEQ): 2,100블록. 세 인덱스 모두 파티션 전환 때 INDEXING 절 없이 만들었다.
  • 고객은 2,000명이고 고객마다 약 500건이 36칸에 고르게 흩어져 있다(한 해 약 167건). 행마다 다른 블록에 있다.
  • 이 테이블을 읽는 SQL(V$SQL, 하루 기준)
    • Q1 상담 「최근 주문」: CUS_ID = :c AND ORD_DT >= :v_from(최근 12개월), IX_P14_CUS_DT, 2만 번
    • Q2 「처리 대기 모니터」: ORD_ST = 'PENDING' AND ORD_DT >= :v_from(최근 7일), IX_P14_ST_DT, 288번
    • Q3 민원 대응 「고객 연도별 주문 요약」: CUS_ID = :c(전 기간), IX_P14_CUS_DT, 20번
    • Q4 「주문번호 조회」: ORD_SEQ = :seq, IX_P14_SEQ, 3만 번

원본 SQL ​

sql
-- 파티션 전환 때 만든 인덱스 (INDEXING 절 없음)
CREATE INDEX IX_P14_CUS_DT ON T_ORD_BIG_P14 (CUS_ID, ORD_DT) LOCAL;
CREATE INDEX IX_P14_ST_DT ON T_ORD_BIG_P14 (ORD_ST, ORD_DT) LOCAL;
CREATE UNIQUE INDEX IX_P14_SEQ ON T_ORD_BIG_P14 (ORD_SEQ);

-- 오과장의 스크립트 (P202201 ~ P202212, 칸마다 한 줄)
ALTER TABLE T_ORD_BIG_P14 MODIFY PARTITION P202201 INDEXING OFF;
ALTER TABLE T_ORD_BIG_P14 MODIFY PARTITION P202202 INDEXING OFF;
-- … P202212 까지

-- Q3 「고객 연도별 주문 요약」
SELECT TO_CHAR(ORD_DT, 'YYYY') AS ord_yy, COUNT(*) AS ord_cnt, SUM(ORD_AMT) AS ord_amt
  FROM T_ORD_BIG_P14
 WHERE CUS_ID = :v_cus
 GROUP BY TO_CHAR(ORD_DT, 'YYYY')

실행계획 학습용 예시 · 교재 14화 실측 규모(고객 1명 500건, LOCAL 인덱스 Starts 36) ​

xplan
[스크립트 뒤 · 사전 정보]
  USER_TAB_PARTITIONS   P202201 ~ P202212  INDEXING = OFF · P202301 ~ PMAX  INDEXING = ON
  USER_INDEXES          IX_P14_CUS_DT  INDEXING = FULL · IX_P14_ST_DT  INDEXING = FULL · IX_P14_SEQ  INDEXING = FULL
  USER_IND_PARTITIONS   IX_P14_CUS_DT, IX_P14_ST_DT 의 37칸 모두 USABLE
  USER_SEGMENTS         IX_P14_CUS_DT 3,240 → 3,240블록 · IX_P14_ST_DT 2,880 → 2,880블록 (스크립트 전 → 뒤)

[Q3 · 스크립트 전과 뒤가 같다]
------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                    | Name          | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                             |               |      1 |        |      3 | 00:00:00.01 |     572 |        |       |
|   1 |  HASH GROUP BY                               |               |      1 |      3 |      3 | 00:00:00.01 |     572 |        |       |
|   2 |   PARTITION RANGE ALL                        |               |      1 |    500 |    500 | 00:00:00.01 |     572 |      1 |    37 |
|   3 |    TABLE ACCESS BY LOCAL INDEX ROWID BATCHED | T_ORD_BIG_P14 |     36 |    500 |    500 | 00:00:00.01 |     572 |      1 |    37 |
|*  4 |     INDEX RANGE SCAN                         | IX_P14_CUS_DT |     36 |    500 |    500 | 00:00:00.01 |      72 |      1 |    37 |
------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   4 - access("CUS_ID"=:V_CUS)

문제 ​

  1. 스크립트가 오류 없이 끝났는데도 인덱스가 줄지 않은 까닭을 사전 정보로 설명하고, 2022년 칸의 로컬 인덱스가 실제로 사라지게 하는 DDL을 쓰시오.
  2. 고친 뒤 Q1 ~ Q4가 각각 어떻게 되는지 쓰고, Q3의 실행계획과 Buffers가 어떻게 바뀌는지 설명하시오.
  3. 이 안으로 얻는 것과 잃는 것을 숫자로 정리하고, IX_P14_SEQ도 같은 방법으로 줄일 수 있는지와 칸의 인덱스를 끄기 전에 확인할 것을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자