테마
한빛유통은 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)-- ① 일 매출
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;
[운영 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)