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

고객의 고액 주문 다섯 건을 보려고 그 고객 주문 500건을 다 읽고 정렬한다

중급SELECT한빛유통396 / 700

상황 ​

한빛유통 VIP 상담 화면에는 「고액 주문 TOP 5」 칸이 있다. 전 기간에서 그 고객의 주문 금액이 큰 다섯 건을 보여 주고, 하루 약 2,000번 호출된다. 파티션 전환 때 조민우가 "인덱스에 금액까지 넣었으니 인덱스를 거꾸로 읽다가 다섯 건에서 멈추겠지" 하며 인덱스를 만들었다. 그런데 계획에는 정렬이 남아 있고 한 번에 572블록을 읽는다. 옮기기 전 T_ORD_BIG에서는 같은 모양의 인덱스로 8블록이었다.

테이블과 인덱스 ​

  • T_ORD_BIG_P14 주문(파티션 복사본, 교재 14화): 1,000,000행 · PARTITION BY RANGE (ORD_DT) 월별 36칸(P202201 ~ P202412)과 빈 PMAX, 모두 37칸. 빈 PMAX는 세그먼트가 없다.
  • 고객은 2,000명이고 고객마다 약 500건이 36칸에 고르게 흩어져 있다(칸마다 약 14건). 행마다 다른 블록에 있다.
  • LOCAL 인덱스 IX_P14_CUS_AMT (CUS_ID, ORD_AMT): 칸마다 높이 2. 다른 인덱스는 모두 LOCAL이다. 통계는 최신이다.
  • 매월 1일 가장 오래된 칸을 DROP하고 새 칸을 만든다(보관 36개월).

원본 SQL ​

sql
SELECT *
  FROM (SELECT ORD_SEQ, ORD_DT, ORD_AMT, ORD_ST
          FROM T_ORD_BIG_P14
         WHERE CUS_ID = :v_cus
         ORDER BY ORD_AMT DESC)
 WHERE ROWNUM <= 5

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

xplan
---------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                      | Name           | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
---------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                               |                |      1 |        |      5 | 00:00:00.01 |     572 |        |       |
|*  1 |  COUNT STOPKEY                                 |                |      1 |        |      5 | 00:00:00.01 |     572 |        |       |
|   2 |   VIEW                                         |                |      1 |    500 |      5 | 00:00:00.01 |     572 |        |       |
|*  3 |    SORT ORDER BY STOPKEY                       |                |      1 |    500 |      5 | 00:00:00.01 |     572 |        |       |
|   4 |     PARTITION RANGE ALL                        |                |      1 |    500 |    500 | 00:00:00.01 |     572 |      1 |    37 |
|   5 |      TABLE ACCESS BY LOCAL INDEX ROWID BATCHED | T_ORD_BIG_P14  |     36 |    500 |    500 | 00:00:00.01 |     572 |      1 |    37 |
|*  6 |       INDEX RANGE SCAN                         | IX_P14_CUS_AMT |     36 |    500 |    500 | 00:00:00.01 |      72 |      1 |    37 |
---------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(ROWNUM<=5)
   3 - filter(ROWNUM<=5)
   6 - access("CUS_ID"=:V_CUS)

문제 ​

  1. 인덱스에 ORD_AMT가 있는데도 정렬이 남고 500건을 다 읽는 까닭을 실행계획의 Starts와 인덱스가 정렬되어 있는 범위로 설명하시오.
  2. SQL은 그대로 두고 다섯 건만 읽고 멈추도록 인덱스를 고치시오. 몇 블록이 될지 어림하시오.
  3. 그렇게 고쳤을 때 월 정리에서 치르는 대가와 그것을 처리하는 SQL을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자