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

이관 리허설에서 첫 월 정리를 돌리자 인덱스 넷이 한꺼번에 UNUSABLE이 되었다

실전DDL한빛유통401 / 700

상황 ​

한빛유통은 T_ORD_BIG을 월별 파티션 T_ORD_BIG_P14로 옮긴다. 보관은 36개월이고, 매월 1일 가장 오래된 달을 DROP한다. 이관 스크립트는 운영 인덱스 넷을 같은 문장으로 다시 만든다. 시험 DB에서 리허설 삼아 첫 월 정리를 돌렸더니 인덱스 넷이 모두 UNUSABLE이 되었고, 아래 네 SQL이 전부 FULL로 바뀌었다. 박팀장: "인덱스마다 LOCAL로 할지, GLOBAL로 할지, 아예 없앨지 근거를 붙여서 정해 와. 월 정리 스크립트도 같이."

테이블과 인덱스 ​

  • T_ORD_BIG_P14 주문(이관 대상, 교재 14화): 1,000,000행 · PARTITION BY RANGE (ORD_DT) 월별 36칸(P202201 ~ P202412)과 빈 PMAX, 모두 37칸. 칸 하나 FULL ≈ 161블록이다.
  • ORD_DT는 DATE이고 전부 자정이다. 하루 주문은 약 913건, ORD_ST는 COMPLETE 90%, PENDING 8%, CANCEL 2%다. 고객은 2,000명이고 고객마다 약 500건(한 달 약 14건)이다. ORD_SEQ는 유일하다.
  • 운영 T_ORD_BIG(파티션 없음)의 인덱스: IX_ORD_BIG_DT_AMT (ORD_DT, ORD_AMT) · UX_ORD_BIG_SEQ (ORD_SEQ) UNIQUE · IX_ORD_BIG_CUS (CUS_ID) · IX_ORD_BIG_ST (ORD_ST)
  • SQL 넷의 호출 빈도: ① 일 매출(정산 화면) 하루 수천 번 ② 주문 단건(고객센터, 주문번호만 안다) 하루 약 2만 번 ③ 미결 독촉(배치) 하루 1번 ④ 고객 최근 3개월(상담 화면) 하루 약 3,000번
  • 이관 뒤 주문 적재는 매일 밤 하루치(약 913건)를 넣는다.

원본 SQL ​

sql
-- ① 일 매출
SELECT COUNT(*), SUM(ORD_AMT) FROM T_ORD_BIG_P14
 WHERE ORD_DT >= :d AND ORD_DT < :d + 1;

-- ② 주문 단건 (주문번호만 안다)
SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_ST, ORD_AMT FROM T_ORD_BIG_P14
 WHERE ORD_SEQ = :seq;

-- ③ 미결 독촉 (지난 7일의 PENDING)
SELECT ORD_SEQ, CUS_ID, ORD_AMT FROM T_ORD_BIG_P14
 WHERE ORD_ST = 'PENDING'
   AND ORD_DT >= TRUNC(SYSDATE) - 7 AND ORD_DT < TRUNC(SYSDATE);

-- ④ 고객 최근 3개월 (이번 달 포함)
SELECT ORD_SEQ, ORD_DT, ORD_AMT FROM T_ORD_BIG_P14
 WHERE CUS_ID = :cus
   AND ORD_DT >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -2)
 ORDER BY ORD_DT DESC;

-- 이관 스크립트의 인덱스 (운영과 같은 문장)
CREATE INDEX IX_ORD_BIG_DT_AMT ON T_ORD_BIG_P14 (ORD_DT, ORD_AMT);
CREATE UNIQUE INDEX UX_ORD_BIG_SEQ ON T_ORD_BIG_P14 (ORD_SEQ);
CREATE INDEX IX_ORD_BIG_CUS ON T_ORD_BIG_P14 (CUS_ID);
CREATE INDEX IX_ORD_BIG_ST ON T_ORD_BIG_P14 (ORD_ST);

-- 월 정리 (매월 1일)
ALTER TABLE T_ORD_BIG_P14 DROP PARTITION P202201;

실행계획 학습용 예시 · 운영 수치는 교재 02화 · 06화 · 14화 규모 ​

xplan
[운영 T_ORD_BIG · 지금의 네 SQL]
--------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name              | Starts | E-Rows | A-Rows | Buffers |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                   |      1 |        |      1 |       5 |
|   1 |  SORT AGGREGATE                       |                   |      1 |      1 |      1 |       5 |
|*  2 |   INDEX RANGE SCAN                    | IX_ORD_BIG_DT_AMT |      1 |    913 |    913 |       5 |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                   |      1 |        |      1 |       4 |
|   1 |  TABLE ACCESS BY INDEX ROWID          | T_ORD_BIG         |      1 |      1 |      1 |       4 |
|*  2 |   INDEX UNIQUE SCAN                   | UX_ORD_BIG_SEQ    |      1 |      1 |      1 |       3 |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                   |      1 |        |    511 |    5826 |
|*  1 |  TABLE ACCESS FULL                    | T_ORD_BIG         |      1 |    520 |    511 |    5826 |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                   |      1 |        |     42 |     504 |
|   1 |  SORT ORDER BY                        |                   |      1 |     42 |     42 |     504 |
|*  2 |   TABLE ACCESS BY INDEX ROWID BATCHED | T_ORD_BIG         |      1 |     42 |     42 |     504 |
|*  3 |    INDEX RANGE SCAN                   | IX_ORD_BIG_CUS    |      1 |    500 |    500 |       4 |
--------------------------------------------------------------------------------------------------------
  (위에서부터 ① ② ③ ④ · ③ 은 PENDING 이 3년 치 8만 건이라 IX_ORD_BIG_ST 를 쓰지 않는다)

[시험 DB · 이관 스크립트 그대로 · 첫 월 정리 뒤]
  USER_INDEXES   네 인덱스 모두 PARTITIONED NO · STATUS UNUSABLE
  ① 161  (6월 칸 FULL)      ② 5,707 (35칸 FULL)
  ③ 322  (두 칸 FULL)       ④ 483  (세 칸 FULL)
  밤 적재 INSERT            ORA-01502 (UX_ORD_BIG_SEQ)

문제 ​

  1. 리허설에서 인덱스 넷이 모두 UNUSABLE이 된 까닭을 쓰시오.
  2. SQL ① ~ ④마다 인덱스를 LOCAL로 둘지, GLOBAL로 둘지, 만들지 않을지 정해 DDL로 작성하고, 각 SQL이 몇 칸을 열고 몇 블록을 읽을지 어림하시오.
  3. 그 설계에 맞는 월 정리 스크립트를 작성하고, 설계의 대가(월 정리, 적재)를 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자