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

파티셔닝 승인이 났는데 주문 테이블을 무엇으로 나눌지 네 사람의 말이 다 다르다

실전DDL한빛유통412 / 700

상황 ​

박팀장이 근거 수치를 들고 파티셔닝 옵션 예산을 받아 냈다. 첫 대상은 T_ORD_BIG이고, 네 사람이 안을 냈다. (가) 조민우는 가장 자주 도는 Q2가 고객으로 찾으니 HASH (CUS_ID) 16칸으로 나누자고 했다. (나) 오과장은 미결 점검 Q4가 PENDING만 보면 되니 LIST (ORD_ST)로 나누자고 했다. (다) 선배는 주문일 월별 INTERVAL을 냈다. (라) 강도현의 옛 메모에는 주문일 월별 칸 안을 HASH (CUS_ID) 8조각으로 나누는 안이 있다. 박팀장: "안마다 SQL 넷에 대어 보고, 하나를 골라 DDL까지 가져와."

테이블과 인덱스 ​

  • T_ORD_BIG 대용량 주문: 1,000,000행 · 5,826블록 · 파티션 없음. ORD_DT는 2022-01-01 ~ 2024-12-31이고 전부 자정이며 한 달은 약 27,400 ~ 28,300행이다.
  • ORD_ST는 COMPLETE 90% · PENDING 8% · CANCEL 2%이고 결제와 취소 때 바뀐다. 고객은 2,000명이고 고객 한 명은 3년에 약 500건(최근 12개월 약 167건)을 주문했다.
  • 지금 인덱스: IX_ORD_BIG_DT_AMT (ORD_DT, ORD_AMT) · IX_ORD_BIG_CUS (CUS_ID, ORD_DT). 통계 최신. 오늘은 2024년 12월 16일이다.
  • 연습 DB에 (가)안을 지어 Q1과 Q3을 재 봤다(아래 실행계획, 인덱스는 같은 두 개를 LOCAL로 만들었다). (다)안 모양은 교재 14화의 T_ORD_BIG_P14와 같다(칸 하나 FULL 161블록, 커버링 LOCAL 인덱스로 한 달 89블록).

원본 SQL ​

sql
-- Q1 「월 마감 일별 매출」 (월초 주간 하루 수백 번)
SELECT ORD_DT, COUNT(*) AS cnt, SUM(ORD_AMT) AS amt
  FROM T_ORD_BIG
 WHERE ORD_DT >= :v_mon
   AND ORD_DT <  ADD_MONTHS(:v_mon, 1)
 GROUP BY ORD_DT;

-- Q2 「고객 주문 내역」 최근 12개월 (하루 약 2만 번)
SELECT ORD_SEQ, ORD_DT, ORD_ST, ORD_AMT
  FROM T_ORD_BIG
 WHERE CUS_ID = :v_cus
   AND ORD_DT >= ADD_MONTHS(TRUNC(SYSDATE), -12)
 ORDER BY ORD_DT DESC;

-- Q3 「보관 정리」 36개월 지난 달 (매월 1일)
DELETE FROM T_ORD_BIG
 WHERE ORD_DT < ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -35);

-- Q4 「미결 점검」 최근 7일 PENDING (매시간)
SELECT COUNT(*) AS cnt, SUM(ORD_AMT) AS amt
  FROM T_ORD_BIG
 WHERE ORD_ST = 'PENDING'
   AND ORD_DT >= TRUNC(SYSDATE) - 7;

실행계획 학습용 예시 · 교재 14화 규모 ​

xplan
[지금 · 파티션 없음 · 한 번 실행]
  Q1  INDEX RANGE SCAN IX_ORD_BIG_DT_AMT (커버링)                  91블록
  Q2  INDEX RANGE SCAN IX_ORD_BIG_CUS + 테이블 167행                171블록
  Q3  DELETE 약 28,000행 · 인덱스 둘도 고친다 · redo 약 10MB · 그 뒤 전체 스캔은 5,826 그대로
  Q4  TABLE ACCESS FULL                                          5,826블록

[(가) HASH (CUS_ID) 16 · Q1 · 2024년 6월]
-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name                | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                     |      1 |        |     30 | 00:00:00.02 |     132 |        |       |
|   1 |  HASH GROUP BY        |                     |      1 |     30 |     30 | 00:00:00.02 |     132 |        |       |
|*  2 |   FILTER              |                     |      1 |        |  27390 | 00:00:00.02 |     132 |        |       |
|   3 |    PARTITION HASH ALL |                     |      1 |  27390 |  27390 | 00:00:00.02 |     132 |      1 |    16 |
|*  4 |     INDEX RANGE SCAN  | IX_ORD_BIG_H_DT_AMT |     16 |  27390 |  27390 | 00:00:00.01 |     132 |      1 |    16 |
-------------------------------------------------------------------------------------------------------------------------

   2 - filter(:V_MON<ADD_MONTHS(:V_MON,1))
   4 - access("ORD_DT">=:V_MON AND "ORD_DT"<ADD_MONTHS(:V_MON,1))

[(가) · Q3 · 2022년 1월]
----------------------------------------------------------------------------------------------------------------
| Id  | Operation            | Name        | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
----------------------------------------------------------------------------------------------------------------
|   0 | DELETE STATEMENT     |             |      1 |        |      0 | 00:00:01.92 |    118K |        |       |
|   1 |  DELETE              | T_ORD_BIG_H |      1 |        |      0 | 00:00:01.92 |    118K |        |       |
|   2 |   PARTITION HASH ALL |             |      1 |  27390 |  28304 | 00:00:00.12 |    5842 |      1 |    16 |
|*  3 |    TABLE ACCESS FULL | T_ORD_BIG_H |     16 |  27390 |  28304 | 00:00:00.10 |    5842 |      1 |    16 |
----------------------------------------------------------------------------------------------------------------

   3 - filter("ORD_DT"<ADD_MONTHS(TRUNC(SYSDATE@!,'fmmm'),-35))

문제 ​

  1. 네 안을 Q1 ~ Q4에 대어 보고, 안마다 칸을 고르는지와 몇 칸을 여는지를 근거로 득실을 정리하시오.
  2. 고른 안의 테이블과 인덱스 DDL을 쓰고, Q3을 대신할 문장과 Q2의 인덱스를 LOCAL과 GLOBAL 가운데 무엇으로 할지 근거와 함께 쓰시오.
  3. 고른 안의 대가와, 해시 서브파티션을 더해야 할 조건을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자