테마
본사 영업기획팀의 「상품별 월 목표 대비 실적」(2023년, 상품 109개 × 12개월 = 1,308줄)은 열 때마다 1.9초가 걸린다. 영업기획팀 20명이 하루 약 400번 연다. 목표는 상품마다 한 줄에 열두 달 칸이 옆으로 늘어선 표 CF_ITM_GOAL에 들어 있어서, 2019년 작성자는 달마다 한 덩어리씩 열두 덩어리를 UNION ALL로 이어 붙였다.
조민우가 UNPIVOT으로 목표를 세로로 세우고 실적을 한 번에 묶는 판을 만들었다. 0.3초로 빨라졌지만 1,261줄만 나왔다. 영업기획팀은 "목표를 잡지 않은 달도 실적은 보여야 한다. 시범 판매나 시즌 연장 실적이 거기 있다"라고 한다.
CF10 판매: 500,000행 · 4,583블록(전체 스캔 4,510) · SLE_DT VARCHAR2(8) · 2023년 250,120건 · 한 달 약 20,800건CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · SLE_QTY · 2023년 줄 약 548,000CF_ITM_GOAL 상품 월 목표(이 문제에서 쓰는 표): GOAL_YY · ITM_NO · M01_QTY ~ M12_QTY · 연도마다 상품 109줄(2년 218행) · 4블록 · PK (GOAL_YY, ITM_NO)IX_CF10_SLE_DT (SLE_DT): BLEVEL 2 · 리프 1,393 · CF 9,921 · 통계 최신-- 지금 SQL (2019년) : 달마다 한 덩어리 · 모두 12 덩어리
SELECT g.ITM_NO, '01' AS MM, g.M01_QTY AS GOAL_QTY, a.ACT_QTY
FROM CF_ITM_GOAL g,
(SELECT d.ITM_NO, SUM(d.SLE_QTY) AS ACT_QTY
FROM CF10 h, CF11 d
WHERE h.SLE_DT BETWEEN '20230101' AND '20230131'
AND d.SLE_NO = h.SLE_NO
GROUP BY d.ITM_NO) a
WHERE g.GOAL_YY = '2023'
AND a.ITM_NO(+) = g.ITM_NO
UNION ALL
SELECT g.ITM_NO, '02', g.M02_QTY, a.ACT_QTY
FROM CF_ITM_GOAL g,
(SELECT d.ITM_NO, SUM(d.SLE_QTY) AS ACT_QTY
FROM CF10 h, CF11 d
WHERE h.SLE_DT BETWEEN '20230201' AND '20230228'
AND d.SLE_NO = h.SLE_NO
GROUP BY d.ITM_NO) a
WHERE g.GOAL_YY = '2023'
AND a.ITM_NO(+) = g.ITM_NO
UNION ALL
-- … 3월 ~ 12월도 같은 모양
ORDER BY 1, 2;
-- 조민우 판 (0.3초 · 1,261줄)
SELECT g.ITM_NO, g.MM, g.GOAL_QTY, a.ACT_QTY
FROM (SELECT ITM_NO, MM, GOAL_QTY
FROM CF_ITM_GOAL
UNPIVOT (GOAL_QTY FOR MM IN (M01_QTY AS '01', M02_QTY AS '02', M03_QTY AS '03', M04_QTY AS '04',
M05_QTY AS '05', M06_QTY AS '06', M07_QTY AS '07', M08_QTY AS '08',
M09_QTY AS '09', M10_QTY AS '10', M11_QTY AS '11', M12_QTY AS '12'))
WHERE GOAL_YY = '2023') g,
(SELECT d.ITM_NO, SUBSTR(h.SLE_DT, 5, 2) AS MM, SUM(d.SLE_QTY) AS ACT_QTY
FROM CF10 h, CF11 d
WHERE h.SLE_DT BETWEEN '20230101' AND '20231231'
AND d.SLE_NO = h.SLE_NO
GROUP BY d.ITM_NO, SUBSTR(h.SLE_DT, 5, 2)) a
WHERE a.ITM_NO(+) = g.ITM_NO
AND a.MM(+) = g.MM
ORDER BY 1, 2;
[지금 SQL · 덩어리 12개 가운데 1월과 12월만 펼쳐 적는다]
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1308 |00:00:01.91 | 104K|
| 1 | SORT ORDER BY | | 1 | 1308 | 1308 |00:00:01.91 | 104K|
| 2 | UNION-ALL | | 1 | | 1308 |00:00:01.90 | 104K|
|* 3 | HASH JOIN OUTER | | 1 | 109 | 109 |00:00:00.16 | 8677 |
|* 4 | TABLE ACCESS FULL | CF_ITM_GOAL | 1 | 109 | 109 |00:00:00.01 | 4 |
| 5 | VIEW | | 1 | 88 | 84 |00:00:00.16 | 8673 |
| 6 | HASH GROUP BY | | 1 | 88 | 84 |00:00:00.16 | 8673 |
|* 7 | HASH JOIN | | 1 | 45900 | 45188 |00:00:00.14 | 8673 |
| 8 | TABLE ACCESS BY INDEX ROWID BATCHED| CF10 | 1 | 20850 | 20611 |00:00:00.01 | 469 |
|* 9 | INDEX RANGE SCAN | IX_CF10_SLE_DT | 1 | 20850 | 20611 |00:00:00.01 | 60 |
| 10 | TABLE ACCESS FULL | CF11 | 1 | 1096K| 1096K|00:00:00.11 | 8204 |
| | (2월 ~ 11월 덩어리 10개 · 모양이 같고 덩어리마다 CF11 FULL 8,204) |
|* 91 | HASH JOIN OUTER | | 1 | 109 | 109 |00:00:00.16 | 8692 |
|* 92 | TABLE ACCESS FULL | CF_ITM_GOAL | 1 | 109 | 109 |00:00:00.01 | 4 |
| 93 | VIEW | | 1 | 88 | 88 |00:00:00.16 | 8688 |
| 94 | HASH GROUP BY | | 1 | 88 | 88 |00:00:00.16 | 8688 |
|* 95 | HASH JOIN | | 1 | 46600 | 46640 |00:00:00.14 | 8688 |
| 96 | TABLE ACCESS BY INDEX ROWID BATCHED| CF10 | 1 | 21250 | 21264 |00:00:00.01 | 484 |
|* 97 | INDEX RANGE SCAN | IX_CF10_SLE_DT | 1 | 21250 | 21264 |00:00:00.01 | 62 |
| 98 | TABLE ACCESS FULL | CF11 | 1 | 1096K| 1096K|00:00:00.11 | 8204 |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("A"."ITM_NO"="G"."ITM_NO")
4 - filter("G"."GOAL_YY"='2023')
7 - access("D"."SLE_NO"="H"."SLE_NO")
9 - access("H"."SLE_DT">='20230101' AND "H"."SLE_DT"<='20230131')
… (덩어리마다 같은 모양 · 97 - access("H"."SLE_DT">='20231201' AND "H"."SLE_DT"<='20231231'))
UNPIVOT의 기본 동작으로 설명하시오.