Skip to content
튜닝 연습서브쿼리와 쿼리 변환
SUBQ-007

날짜는 30개뿐인데 그날 매출 합계를 4,110번 다시 구한다

중급SELECT한빛유통242 / 700

상황 ​

정산팀의 「주문별 일 매출 비중」 리포트는 지난달 주문마다 그날 전체 매출에서 차지하는 비중(%)을 보여 준다. 월초 일주일 동안 담당자 다섯 명이 하루 수십 번 돌리는데, 한 번에 1.6초 걸린다. SQL을 짠 조민우는 "서브쿼리 안에서 TRUNC로 날짜만 남겼으니, 캐시가 날짜 30개만 계산하고 나머지는 꺼내 쓸 줄 알았다"라고 했다. 아래는 2024년 6월 치다.

테이블과 인덱스 ​

  • T_ORD: 100,000행 · 896블록 · ORD_DT DATE(시분초 있음) · 2023-01-01 ~ 2024-12-30, 하루 137건 · 2024년 6월 4,110건
  • T_ORD는 ORD_SEQ 순서로 쌓여 있고, 같은 날의 주문은 730행 간격으로 테이블 전체에 흩어져 있다
  • 인덱스: PK_T_ORD (ORD_SEQ) · IX_T_ORD_DT (ORD_DT) · 통계 최신

원본 SQL ​

sql
SELECT o.ORD_SEQ, o.ORD_DT, o.CUS_ID, o.ORD_AMT,
       ROUND(o.ORD_AMT * 100 /
             (SELECT SUM(x.ORD_AMT)
                FROM T_ORD x
               WHERE x.ORD_DT >= TRUNC(o.ORD_DT)
                 AND x.ORD_DT <  TRUNC(o.ORD_DT) + 1), 2) AS day_pct
  FROM T_ORD o
 WHERE o.ORD_DT >= DATE '2024-06-01'
   AND o.ORD_DT <  DATE '2024-07-01'
 ORDER BY o.ORD_DT

실행계획 학습용 예시 ​

xplan
-------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |             |      1 |        |   4110 |00:00:01.58 |     572K|
|   1 |  SORT AGGREGATE                       |             |   4110 |      1 |   4110 |00:00:01.52 |     571K|
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED | T_ORD       |   4110 |    137 |    563K|00:00:01.31 |     571K|
|*  3 |    INDEX RANGE SCAN                   | IX_T_ORD_DT |   4110 |    137 |    563K|00:00:00.24 |    8220 |
|   4 |  SORT ORDER BY                        |             |      1 |   4110 |   4110 |00:00:01.58 |     572K|
|*  5 |   TABLE ACCESS FULL                   | T_ORD       |      1 |   4110 |   4110 |00:00:00.01 |     896 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("X"."ORD_DT">=TRUNC(:B1) AND "X"."ORD_DT"<TRUNC(:B1)+1)
   5 - filter(("O"."ORD_DT">=TO_DATE(' 2024-06-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "O"."ORD_DT"<TO_DATE(' 2024-07-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))

(DBMS_XPLAN 이 줄여 쓴 값 — 563K = 563,070 · 571K = 571,290 · 572K = 572,186)

문제 ​

  1. 1번 줄의 Starts 4,110이 무엇의 개수인지 쓰고, 날짜가 30개뿐인데도 캐시가 한 번도 듣지 않은 이유를 Predicate Information으로 설명하시오.
  2. 결과가 바뀌지 않게 SQL을 고치시오. 고친 방법이 목록에 조건이 더 붙을 때도 같은 답을 내는지 함께 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자