Skip to content
튜닝 연습소트 튜닝과 페이징
SORT-047

금액이 두 배로 나와 DISTINCT를 붙였더니 이번에는 주문 금액이 원장의 73%로 찍힌다

중급SELECT한빛유통352 / 700

상황 ​

정산팀의 「월별 주문 판매 집계」는 기간(기본 최근 1년)의 주문을 달별로 묶어 주문 수, 주문 금액, 주문상세 줄 수, 판매 수량을 보여 준다. 2022년에 처음 만들 때 주문 금액이 원장의 두 배쯤으로 나와서, 개발자가 주문 수와 주문 금액에 DISTINCT를 붙여 고쳤다. 그때는 주문 수가 원장과 맞는 것만 확인했다. 이번 분기 재무팀이 2024년 6월 주문 금액(905,627,800원)이 원장(1,241,286,300원)의 73%라며 반려했다. 박팀장은 "숫자를 맞추고, 왜 그렇게 됐는지와 비용도 같이 정리해 달라"고 했다.

테이블과 인덱스 ​

  • T_ORD 주문: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ) · ORD_DT는 시분초 있음 · ORD_AMT는 100원 단위다. 2024년 주문은 50,112건, 6월은 4,110건이다.
  • T_ORD_DET 주문상세: 200,000행 · 896블록 · PK_T_ORD_DET (ORD_SEQ, ORD_DET_NO) · 주문당 1 ~ 3줄(평균 2.0줄). 2024년 주문의 상세는 100,224줄이다.
  • 주문상세가 없는 주문은 지금 0건이다. 금액이 같은 주문은 흔하다(6월 4,110건의 서로 다른 금액은 2,996가지).
  • 원장은 T_ORD만 달별로 더한 값이다. 통계는 최신이다.

원본 SQL ​

sql
SELECT TO_CHAR(o.ORD_DT, 'YYYYMM')  AS ym,
       COUNT(DISTINCT o.ORD_SEQ)    AS ord_cnt,
       SUM(DISTINCT o.ORD_AMT)      AS ord_amt,      -- 2022.08 : 금액이 두 배로 나와 DISTINCT 를 붙였다
       COUNT(*)                     AS det_lines,
       SUM(d.ORD_QTY)               AS sale_qty
  FROM T_ORD o, T_ORD_DET d
 WHERE o.ORD_DT >= :from_dt AND o.ORD_DT < :to_dt
   AND d.ORD_SEQ = o.ORD_SEQ
 GROUP BY TO_CHAR(o.ORD_DT, 'YYYYMM')
 ORDER BY ym

실행계획 학습용 예시 ​

xplan
[2024년 1월 ~ 12월]
-----------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |           |      1 |        |     12 |00:00:00.21 |    1792 |          |
|   1 |  SORT GROUP BY        |           |      1 |     12 |     12 |00:00:00.21 |    1792 | 6144K (0)|
|*  2 |   FILTER              |           |      1 |        |    100K|00:00:00.13 |    1792 |          |
|*  3 |    HASH JOIN          |           |      1 |    100K|    100K|00:00:00.12 |    1792 | 3712K (0)|
|*  4 |     TABLE ACCESS FULL | T_ORD     |      1 |  50000 |  50112 |00:00:00.01 |     896 |          |
|   5 |     TABLE ACCESS FULL | T_ORD_DET |      1 |    200K|    200K|00:00:00.02 |     896 |          |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(:FROM_DT<:TO_DT)
   3 - access("D"."ORD_SEQ"="O"."ORD_SEQ")
   4 - filter(("O"."ORD_DT">=:FROM_DT AND "O"."ORD_DT"<:TO_DT))

[6월 한 줄 · 원장과 대조]
          ORD_CNT         ORD_AMT   DET_LINES   SALE_QTY
  화면       4,110     905,627,800       8,231     16,508
  원장       4,110   1,241,286,300

문제 ​

  1. 2022년에 금액이 두 배로 나온 까닭과, DISTINCT를 붙인 뒤 주문 수는 맞는데 금액만 작아진 까닭을 설명하시오.
  2. DISTINCT 없이 원장과 맞는 SQL로 고치시오. DISTINCT 집계가 실행계획에서 무엇을 더 시키는지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자