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

칸을 하나만 여는데도 한 달 조회가 한 해 치를 읽는다

기초DDL버거404 / 700

상황 ​

본사 분석팀이 주문을 주문일 기준 월별 파티션 ORD_RANGE_DT로 새로 지었다. 한빛유통 T_ORD_BIG_P14의 생성 스크립트를 본떠 쓰면서, DATE 리터럴 자리에 같은 날짜를 문자열로 넣었다. 그런데 「월 매장 실적」이 기존 ORD_RANGE보다 오히려 느리다. 조민우: "실행계획을 보면 칸 하나만 열거든요. 파티션은 잘 타는데요."

테이블과 인덱스 ​

  • ORD_RANGE_DT 주문(파티션 복사본, 문제 설정): ORD 1,000,000행을 PARTITION BY RANGE (ORD_DT) 월별 24칸(P201201 ~ P201312)과 PMAX로 나눠 CTAS로 지었다. 경계는 아래 DDL과 같다.
  • ORD_DT는 VARCHAR2(8) '20120601' 형식이다. 2012년은 약 500,700행, 2012년 6월은 41,040행이다. 같은 데이터를 한 달씩 제대로 나누면 칸 하나는 FULL로 약 935블록이다.
  • 인덱스는 없다. 통계는 최신이다.

원본 SQL ​

sql
CREATE TABLE ORD_RANGE_DT
PARTITION BY RANGE (ORD_DT)
( PARTITION P201201 VALUES LESS THAN ('2012-02-01'),
  PARTITION P201202 VALUES LESS THAN ('2012-03-01'),
  -- … 월마다 한 줄
  PARTITION P201212 VALUES LESS THAN ('2013-01-01'),
  PARTITION P201301 VALUES LESS THAN ('2013-02-01'),
  -- …
  PARTITION P201312 VALUES LESS THAN ('2014-01-01'),
  PARTITION PMAX    VALUES LESS THAN (MAXVALUE) )
AS SELECT * FROM ORD;

-- 「월 매장 실적」 (:v_from = '20120601', :v_to = '20120630')
SELECT SHOP_NO, COUNT(*) AS ord_cnt
  FROM ORD_RANGE_DT
 WHERE ORD_DT BETWEEN :v_from AND :v_to
 GROUP BY SHOP_NO;

실행계획 학습용 예시 ​

xplan
------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |      1 |        |    200 | 00:00:00.21 |   11236 |        |       |
|   1 |  HASH GROUP BY              |              |      1 |    200 |    200 | 00:00:00.21 |   11236 |        |       |
|*  2 |   FILTER                    |              |      1 |        |  41040 | 00:00:00.19 |   11236 |        |       |
|   3 |    PARTITION RANGE ITERATOR |              |      1 |  41012 |  41040 | 00:00:00.19 |   11236 |    KEY |   KEY |
|*  4 |     TABLE ACCESS FULL       | ORD_RANGE_DT |      1 |  41012 |  41040 | 00:00:00.18 |   11236 |    KEY |   KEY |
------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(:V_FROM<=:V_TO)
   4 - filter(("ORD_DT">=:V_FROM AND "ORD_DT"<=:V_TO))

  (실행 때 고른 칸 — 12번 P201212)

[USER_TAB_PARTITIONS · 통계 수집 뒤]
  PARTITION_NAME       POSITION  HIGH_VALUE        NUM_ROWS   BLOCKS
  P201201 ~ P201211      1 ~ 11  '2012-02-01' …           0        0
  P201212                    12  '2013-01-01'       500,684   11,230
  P201301 ~ P201311     13 ~ 23  '2013-02-01' …           0        0
  P201312                    24  '2014-01-01'       499,316   11,192
  PMAX                       25  MAXVALUE                 0        0

문제 ​

  1. 칸 하나만 열었는데 한 달 치의 열 배가 넘는 블록을 읽은 까닭을 파티션 통계와 경계값으로 설명하시오.
  2. 한 칸에 한 달 치만 들어가도록 DDL을 고쳐 쓰고, 고친 뒤 6월 조회가 몇 블록을 읽을지와 지은 뒤 무엇을 확인할지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자