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

대시보드의 「6월 구매 고객」이 21,947명인데 고객은 2,000명뿐이다

실전INSERT한빛유통360 / 700

상황 ​

경영지원팀 대시보드의 「구매 고객」 칸은 어제까지의 주문 수, 주문 금액, 구매 고객 수(같은 고객은 한 번)를 일, 주, 월 추이로 보여 준다. 07시부터 19시까지 1분마다 새로 고쳐 하루 720번 돈다. 처음에는 화면이 T_ORD_BIG에서 바로 셌는데 너무 무거워서, 작년에 조민우가 일 요약 표 T_DASH_DAY를 만들었다. 06시 30분 배치가 전날 한 줄을 넣고, 화면은 그 표를 주와 달로 더한다. 어제 박팀장이 임원 회의에서 「6월 구매 고객 21,947명」이라고 보고했다가 "고객이 2천 명인데 무슨 숫자냐"는 질문을 받았다. 박팀장은 "주문 수와 금액은 맞다는데 고객 수는 왜 틀렸는지 밝히고, 고칠 안을 모두 모아 비용과 대가를 붙여 가져오라"고 했다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT 전부 자정 · IX_ORD_BIG_DT (ORD_DT) · 하루 약 912건을 고객 2,000명이 고르게 산다. 하루 구매 고객은 약 730명, 한 주는 약 1,920명, 한 달은 2,000명이다.
  • T_DASH_DAY 일 요약: BS_DT(PK) · ORD_CNT · ORD_AMT · CUS_CNT · 1,096행 · 8블록. 06:30 배치가 전날 한 줄을 넣는다.
  • 화면은 일 추이(최근 30일), 주 추이(최근 12주, 월요일 시작), 월 추이(이번 달 포함 13개월) 세 SQL을 보낸다. 오늘 주문은 보여 주지 않는다.
  • 통계는 최신이다.

원본 SQL ​

sql
-- [06:30 배치] 전날 한 줄
INSERT INTO T_DASH_DAY (BS_DT, ORD_CNT, ORD_AMT, CUS_CNT)
SELECT TRUNC(SYSDATE) - 1, COUNT(*), SUM(ORD_AMT), COUNT(DISTINCT CUS_ID)
  FROM T_ORD_BIG
 WHERE ORD_DT >= TRUNC(SYSDATE) - 1
   AND ORD_DT <  TRUNC(SYSDATE);
COMMIT;

-- [화면 · 월 추이] (주 추이는 TRUNC(BS_DT, 'IW'), 일 추이는 BS_DT 로 같은 모양)
SELECT TRUNC(BS_DT, 'MM') AS mon,
       SUM(ORD_CNT) AS ord_cnt, SUM(ORD_AMT) AS ord_amt, SUM(CUS_CNT) AS cus_cnt
  FROM T_DASH_DAY
 WHERE BS_DT >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -12)
 GROUP BY TRUNC(BS_DT, 'MM')
 ORDER BY mon;

실행계획 학습용 예시 ​

xplan
[작년까지 · 화면이 원본에서 바로 세던 월 추이 (한 번)]
-------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |           |      1 |        |     13 |00:00:00.58 |    5826 |          |
|   1 |  SORT GROUP BY      |           |      1 |     13 |     13 |00:00:00.58 |    5826 | 9216K (0)|
|*  2 |   TABLE ACCESS FULL | T_ORD_BIG |      1 |    361K|    361K|00:00:00.06 |    5826 |          |
-------------------------------------------------------------------------------------------------------
  (일 · 주 · 월 세 SQL × 1분마다 하루 720번 = 하루 약 1,258만 블록)

[지금 · 06:30 배치 (하루 한 번)]  IX_ORD_BIG_DT 범위 4 + 테이블 6 · Buffers 10

[지금 · 화면 월 추이 (한 번)]
-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |               |      1 |        |     13 |00:00:00.01 |       3 |          |
|   1 |  SORT GROUP BY                        |               |      1 |     13 |     13 |00:00:00.01 |       3 | 2048 (0) |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED | T_DASH_DAY    |      1 |    395 |    395 |00:00:00.01 |       3 |          |
|*  3 |    INDEX RANGE SCAN                   | PK_T_DASH_DAY |      1 |    395 |    395 |00:00:00.01 |       2 |          |
-------------------------------------------------------------------------------------------------------------------------

[결과 · 2024년 6월]
                       ORD_CNT   ORD_AMT      CUS_CNT
  T_DASH_DAY 를 더한 값  27,390   (원장과 같다)   21,947
  T_ORD_BIG 원장         27,390   (원장과 같다)    2,000   ← COUNT(DISTINCT CUS_ID)

문제 ​

  1. 주문 수와 금액은 맞는데 구매 고객 수만 틀린 까닭을 설명하시오. 일 요약을 주와 달로 더하는 방식으로는 왜 고칠 수 없는지도 쓰시오.
  2. 정확한 구매 고객 수를 일, 주, 월로 보여 줄 수 있는 안을 셋 이상 들고, 화면 한 번과 하루의 일량, 정확성, 대가를 비교하시오.
  3. 하나를 골라 배치와 화면 SQL을 작성하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자