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

결제일 하루치 정산이 주문 테이블을 통째로 읽는다

실전SELECT한빛유통389 / 700

상황 ​

결제팀의 「결제일 기준 일 정산」은 결제일 하루를 골라 결제수단별 건수와 금액을 낸다. 결제팀 화면과 정산 대사 배치에서 하루 약 1,500번 호출된다. 지난달 T_ORD를 주문일 기준 월별 파티션 T_ORD_P로 옮긴 뒤 다른 화면은 빨라졌는데 이 조회만 그대로다. 결제팀 규정상 주문 후 72시간 안에 결제되지 않은 주문은 자동 취소 배치가 CANCEL로 바꾸고, 그 뒤에는 결제를 받지 않는다.

테이블과 인덱스 ​

  • T_ORD_P 주문(파티션 복사본, 문제 설정): T_ORD 100,000행을 PARTITION BY RANGE (ORD_DT) 월별 24칸(P202301 ~ P202412)과 빈 PMAX로 나눠 CTAS로 지었다(STORAGE (INITIAL 64K)). 칸 하나는 약 4,170행이고 FULL로 약 38블록, 24칸 전체는 약 912블록이다.
  • ORD_DT는 시분초가 있다. PAY_DT는 결제 시각이고 결제 전이면 NULL이다. 실측한 MAX(PAY_DT - ORD_DT)는 2.97일이다. 결제일 하루는 약 137건이다.
  • PAY_TP는 결제수단 4종, PAY_AMT는 결제 금액이다.
  • 인덱스는 LOCAL PK_T_ORD_P (ORD_SEQ, ORD_DT)뿐이다. 통계는 최신이다.
  • 매달 1일 보관 기간(24개월)이 지난 달을 DROP PARTITION으로 정리한다.

원본 SQL ​

sql
SELECT PAY_TP, COUNT(*) AS pay_cnt, SUM(PAY_AMT) AS pay_amt
  FROM T_ORD_P
 WHERE PAY_DT >= TO_DATE(:v_pay_dt, 'YYYYMMDD')
   AND PAY_DT <  TO_DATE(:v_pay_dt, 'YYYYMMDD') + 1
 GROUP BY PAY_TP

실행계획 학습용 예시 ​

xplan
[:v_pay_dt = '20240612']
--------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name    | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |         |      1 |        |      4 | 00:00:00.02 |     912 |        |       |
|   1 |  HASH GROUP BY         |         |      1 |      4 |      4 | 00:00:00.02 |     912 |        |       |
|*  2 |   FILTER               |         |      1 |        |    137 | 00:00:00.02 |     912 |        |       |
|   3 |    PARTITION RANGE ALL |         |      1 |    250 |    137 | 00:00:00.02 |     912 |      1 |    25 |
|*  4 |     TABLE ACCESS FULL  | T_ORD_P |     24 |    250 |    137 | 00:00:00.02 |     912 |      1 |    25 |
--------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_DATE(:V_PAY_DT,'YYYYMMDD')<TO_DATE(:V_PAY_DT,'YYYYMMDD')+1)
   4 - filter(("PAY_DT">=TO_DATE(:V_PAY_DT,'YYYYMMDD') AND "PAY_DT"<TO_DATE(:V_PAY_DT,'YYYYMMDD')+1))

문제 ​

  1. 이 조회가 칸을 전부 여는 까닭을 실행계획과 파티션 키로 설명하시오.
  2. 세 가지 안(주문일 조건을 더한다, PAY_DT에 LOCAL 인덱스를 만든다, PAY_DT에 GLOBAL 인덱스를 만든다)을 SQL과 DDL로 쓰고, 읽는 블록 수와 부작용을 비교하시오.
  3. 권하는 안을 고르고, 그 안이 결과를 바꾸지 않으려면 무엇이 지켜져야 하며 그것을 어떻게 확인하고 지킬지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자