Skip to content
튜닝 연습조인 튜닝
JOIN-029

금액 구간별 수수료 집계의 건수를 다 더하면 그해 주문 수보다 271건 많다

중급SELECT한빛유통179 / 700

상황 ​

정산팀의 「금액 구간별 PG 수수료」는 2024년 주문을 월마다 PG사 수수료 구간표에 맞춰 구간별 건수, 금액, 수수료를 낸다. 재무팀이 구간별 건수를 더해 보니 333,516건으로, 그해 주문 333,245건보다 271건 많아 반려했다. 개발자는 해시 조인이 빠르다며 USE_HASH를 달았는데 실행계획에는 MERGE JOIN이 나온다. 박팀장은 "숫자부터 맞추고, 조인도 제대로 정리해 달라"라고 했다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · 인덱스 없음 · 2024년 주문 333,245건 · ORD_AMT는 10,000 ~ 500,000원 사이 100원 단위 (서로 다른 값 4,901개, 값마다 2024년에 약 68건)
  • T_FEE_BAND PG 수수료 구간표 (이 문제에서 쓰는 파생 테이블): 5행 · 4블록 · BAND_CD · LO_AMT · HI_AMT · FEE_RT
  • 구간표의 값: 0 ~ 50,000 (3.5%) · 50,000 ~ 100,000 (3.0%) · 100,000 ~ 200,000 (2.5%) · 200,000 ~ 300,000 (2.2%) · 300,000 ~ 999,999,999 (2.0%). 앞 구간의 HI_AMT와 다음 구간의 LO_AMT가 같다 (PG사 계약서: "하한 이상, 상한 미만")
  • 통계 최신

원본 SQL ​

sql
SELECT /*+ USE_HASH(o b) */
       TO_CHAR(o.ORD_DT, 'YYYYMM') AS ym, b.BAND_CD,
       COUNT(*) AS ord_cnt, SUM(o.ORD_AMT) AS ord_amt,
       SUM(o.ORD_AMT * b.FEE_RT) AS fee_amt
  FROM T_ORD_BIG o, T_FEE_BAND b
 WHERE o.ORD_DT >= DATE '2024-01-01'
   AND o.ORD_DT <  DATE '2025-01-01'
   AND o.ORD_AMT BETWEEN b.LO_AMT AND b.HI_AMT
 GROUP BY TO_CHAR(o.ORD_DT, 'YYYYMM'), b.BAND_CD

실행계획 학습용 예시 · 행 수는 실데이터 분포로 계산 ​

xplan
---------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |            |      1 |        |     60 |00:00:00.71 |    5830 |       |       |          |
|   1 |  HASH GROUP BY        |            |      1 |     60 |     60 |00:00:00.71 |    5830 |  1270K|  1270K| 1123K (0)|
|   2 |   MERGE JOIN          |            |      1 |   8331 |    333K|00:00:00.62 |    5830 |       |       |          |
|   3 |    SORT JOIN          |            |      1 |      5 |      5 |00:00:00.01 |       4 |  2048 |  2048 | 2048  (0)|
|   4 |     TABLE ACCESS FULL | T_FEE_BAND |      1 |      5 |      5 |00:00:00.01 |       4 |       |       |          |
|*  5 |    FILTER             |            |      5 |        |    333K|00:00:00.55 |    5826 |       |       |          |
|*  6 |     SORT JOIN         |            |      5 |    333K|   1087K|00:00:00.47 |    5826 |  9876K|  1101K| 8778K (0)|
|*  7 |      TABLE ACCESS FULL| T_ORD_BIG  |      1 |    333K|    333K|00:00:00.06 |    5826 |       |       |          |
---------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   5 - filter("O"."ORD_AMT"<="B"."HI_AMT")
   6 - access(INTERNAL_FUNCTION("O"."ORD_AMT")>=INTERNAL_FUNCTION("B"."LO_AMT"))
       filter(INTERNAL_FUNCTION("O"."ORD_AMT")>=INTERNAL_FUNCTION("B"."LO_AMT"))
   7 - filter(("O"."ORD_DT">=TO_DATE(' 2024-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "O"."ORD_DT"<TO_DATE(' 2025-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))

[결과 대조]  구간별 건수 합계 333,516 · 2024년 주문 333,245 · 차이 271

문제 ​

  1. 건수가 271건 많은 이유를 구간표의 값과 조인 조건으로 설명하시오. USE_HASH가 무시된 이유도 설명하시오.
  2. 결과가 맞도록 조인 조건을 고치고, 부등호 조인에 대는 행을 줄이도록 SQL을 다시 작성하시오.
  3. 고친 SQL이 맞다는 것을 무엇과 어떻게 대조해 보일지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자