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

매장 포털은 빨라졌는데 본사의 월 판매 집계만 판매 테이블 120칸을 다 연다

중급SELECT유통410 / 700

상황 ​

유통 본사는 매장 포털을 위해 판매를 "매장별, 월별 칸"으로 나눈 복사본 CF10_SR을 만들었다. 매장 포털의 「매장 월 판매」(하루 수천 번)는 칸 하나만 읽어 빨라졌다. 그런데 본사 영업관리팀의 「월 판매 집계」(전 매장, 월초 하루 수십 번)는 월별로만 나눈 예전 CF10_P보다 오히려 느리다.

테이블과 인덱스 ​

  • CF10_SR 판매(파티션 복사본, 문제 설정): CF10 500,000행을 두 컬럼 범위 키 PARTITION BY RANGE (SHP_NO, SLE_DT)로 나눠 CTAS로 지었다(STORAGE (INITIAL 64K)). 매장마다 월별 24칸(P1001_202201 ~ P1001_202312 …)과 매장별 MAXVALUE 칸이 있고 맨 끝에 PMAX가 있어 모두 126칸이다. 데이터가 있는 칸은 120개이고, 칸 하나는 약 4,170행, FULL로 약 39블록이다.
  • 판매가 있는 매장은 다섯 곳(SHP_NO 1001 ~ 1005, NUMBER)이다. SLE_DT는 VARCHAR2(8)이다. 2023년 6월 전 매장 판매는 20,953건이다.
  • CF10_P(월별 24칸): 칸 하나 FULL ≈ 191블록이다.
  • 인덱스는 CF10_SR_PK (SLE_NO) GLOBAL뿐이다. 통계는 최신이다.

원본 SQL ​

sql
CREATE TABLE CF10_SR
STORAGE (INITIAL 64K)
PARTITION BY RANGE (SHP_NO, SLE_DT)
( PARTITION P1001_202201 VALUES LESS THAN (1001, '20220201'),
  -- … 1001번 매장의 달마다 한 줄
  PARTITION P1001_202312 VALUES LESS THAN (1001, '20240101'),
  PARTITION P1001_MAX    VALUES LESS THAN (1001, MAXVALUE),
  PARTITION P1002_202201 VALUES LESS THAN (1002, '20220201'),
  -- … 1005번 매장까지 같은 모양
  PARTITION PMAX         VALUES LESS THAN (MAXVALUE, MAXVALUE) )
AS SELECT * FROM CF10;

-- Q1 매장 포털 「매장 월 판매」 (하루 수천 번)
SELECT SLE_DT, COUNT(*) AS sle_cnt
  FROM CF10_SR
 WHERE SHP_NO = :v_shp
   AND SLE_DT BETWEEN :v_from AND :v_to
 GROUP BY SLE_DT;

-- Q2 본사 「월 판매 집계」 (월초 하루 수십 번)
SELECT SHP_NO, COUNT(*) AS sle_cnt, COUNT(DISTINCT SLE_DT) AS sle_days
  FROM CF10_SR
 WHERE SLE_DT BETWEEN :v_from AND :v_to
 GROUP BY SHP_NO;

-- Q3 본사 「매장 연간 추이」 (분기마다 몇 번) : SHP_NO = :v_shp AND SLE_DT 한 해

실행계획 학습용 예시 ​

xplan
[Q1 · 1003번 매장 · 2023년 6월]
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |      1 |        |     30 | 00:00:00.01 |      39 |        |       |
|   1 |  HASH GROUP BY              |         |      1 |     30 |     30 | 00:00:00.01 |      39 |        |       |
|*  2 |   FILTER                    |         |      1 |        |   4188 | 00:00:00.01 |      39 |        |       |
|   3 |    PARTITION RANGE ITERATOR |         |      1 |   4170 |   4188 | 00:00:00.01 |      39 |    KEY |   KEY |
|*  4 |     TABLE ACCESS FULL       | CF10_SR |      1 |   4170 |   4188 | 00:00:00.01 |      39 |    KEY |   KEY |
-------------------------------------------------------------------------------------------------------------------

   2 - filter(:V_FROM<=:V_TO)
   4 - filter(("SHP_NO"=:V_SHP AND "SLE_DT">=:V_FROM AND "SLE_DT"<=:V_TO))

  (실행 때 고른 칸 — 1003번 매장의 2023년 6월 칸 하나)

[Q2 · 2023년 6월 · 전 매장]
--------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name    | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |         |      1 |        |      5 | 00:00:00.09 |    4690 |        |       |
|   1 |  SORT GROUP BY         |         |      1 |      5 |      5 | 00:00:00.09 |    4690 |        |       |
|*  2 |   FILTER               |         |      1 |        |  20953 | 00:00:00.08 |    4690 |        |       |
|   3 |    PARTITION RANGE ALL |         |      1 |  20800 |  20953 | 00:00:00.08 |    4690 |      1 |   126 |
|*  4 |     TABLE ACCESS FULL  | CF10_SR |    120 |  20800 |  20953 | 00:00:00.07 |    4690 |      1 |   126 |
--------------------------------------------------------------------------------------------------------------

   2 - filter(:V_FROM<=:V_TO)
   4 - filter(("SLE_DT">=:V_FROM AND "SLE_DT"<=:V_TO))

[Q3 · 1003번 매장 · 2023년]  PARTITION RANGE ITERATOR · KEY / KEY · Starts 12 · Buffers 468

문제 ​

  1. Q1은 칸 하나만 여는데 Q2는 칸을 전부 여는 까닭을 파티션 키의 컬럼 순서로 설명하시오.
  2. Q1의 이점을 지키면서 Q2도 그달 칸만 읽도록 다시 설계해 DDL을 쓰고, Q1 ~ Q3의 Buffers가 어떻게 바뀌는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자