테마
마케팅팀의 「재주문 간격 분포」는 2024년 주문마다 같은 고객의 직전 주문과 며칠 떨어졌는지를 구해 다섯 구간(0일, 1일, 2 ~ 3일, 4 ~ 7일, 8일 이상)으로 센다. 매주 월요일 회의 자료에 붙이고, 담당자가 구간을 바꿔 가며 하루 수십 번 돌린다. 다섯 줄짜리 결과인데 2초 가까이 걸린다. 개발자는 "고객마다 주문에 번호를 매기고, n번 주문과 n+1번 주문을 짝지었다"라고 설명한다.
T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT는 전부 자정 · ORD_SEQ는 유일하다. 2024년 주문은 333,245건이고 고객 2,000명 모두 2024년 주문이 있다(고객당 약 167건).SELECT CASE WHEN gap = 0 THEN '0일'
WHEN gap = 1 THEN '1일'
WHEN gap <= 3 THEN '2~3일'
WHEN gap <= 7 THEN '4~7일'
ELSE '8일 이상' END AS gap_band,
COUNT(*) AS ord_cnt
FROM (SELECT b.ORD_DT - a.ORD_DT AS gap
FROM (SELECT CUS_ID, ORD_DT,
ROW_NUMBER() OVER (PARTITION BY CUS_ID ORDER BY ORD_DT) AS rn
FROM T_ORD_BIG
WHERE ORD_DT >= DATE '2024-01-01'
AND ORD_DT < DATE '2025-01-01') a,
(SELECT CUS_ID, ORD_DT,
ROW_NUMBER() OVER (PARTITION BY CUS_ID ORDER BY ORD_DT) AS rn
FROM T_ORD_BIG
WHERE ORD_DT >= DATE '2024-01-01'
AND ORD_DT < DATE '2025-01-01') b
WHERE b.CUS_ID = a.CUS_ID
AND b.rn = a.rn + 1)
GROUP BY CASE WHEN gap = 0 THEN '0일'
WHEN gap = 1 THEN '1일'
WHEN gap <= 3 THEN '2~3일'
WHEN gap <= 7 THEN '4~7일'
ELSE '8일 이상' END
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 5 |00:00:01.93 | 11652 | |
| 1 | HASH GROUP BY | | 1 | 5 | 5 |00:00:01.93 | 11652 | 1035K (0)|
|* 2 | HASH JOIN | | 1 | 333K| 331K|00:00:01.81 | 11652 | 12M (0)|
| 3 | VIEW | | 1 | 333K| 333K|00:00:00.52 | 5826 | |
| 4 | WINDOW SORT | | 1 | 333K| 333K|00:00:00.47 | 5826 | 10M (0)|
|* 5 | TABLE ACCESS FULL | T_ORD_BIG | 1 | 333K| 333K|00:00:00.09 | 5826 | |
| 6 | VIEW | | 1 | 333K| 333K|00:00:00.55 | 5826 | |
| 7 | WINDOW SORT | | 1 | 333K| 333K|00:00:00.49 | 5826 | 10M (0)|
|* 8 | TABLE ACCESS FULL | T_ORD_BIG | 1 | 333K| 333K|00:00:00.09 | 5826 | |
---------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"."CUS_ID"="A"."CUS_ID" AND "B"."RN"="A"."RN"+1)
5 - filter(("ORD_DT">=TO_DATE(' 2024-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"ORD_DT"<TO_DATE(' 2025-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
8 - filter(("ORD_DT">=TO_DATE(' 2024-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"ORD_DT"<TO_DATE(' 2025-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))