테마
유통 본사 매장 관리 화면의 「최근 판매 추이」 그래프는 매장마다 최근 1주, 4주, 13주 판매 건수를 막대 세 개로 보여 준다. 점장과 본사 담당자가 하루 수백 번 열고, 한 번에 0.3초가 걸린다.
지난주 조민우가 "판매 테이블을 세 번 읽는다"며 한 번만 읽도록 고쳤는데, 시험 화면에서 4주와 13주 막대가 원래보다 낮게 나와 반영을 미뤘다. 아래는 기준일 2023-12-31(1주 20231225 ~, 4주 20231204 ~, 13주 20231002 ~)로 연 화면이다.
CF10 판매: 500,000행 · 4,583블록 · SLE_DT VARCHAR2(8) · SHP_NO NUMBER(5) 1001 ~ 1005 · 이 문제에서는 CF10_PK (SLE_NO) 말고는 인덱스가 없다:v_w1, :v_w4, :v_w13, :v_to)로 넘긴다 · 결과는 15행(3기간 × 5매장)-- 원래 SQL (운영 중)
SELECT '01W' AS PRD, SHP_NO, COUNT(*) AS SLE_CNT
FROM CF10
WHERE SLE_DT BETWEEN :v_w1 AND :v_to
GROUP BY SHP_NO
UNION ALL
SELECT '04W', SHP_NO, COUNT(*)
FROM CF10
WHERE SLE_DT BETWEEN :v_w4 AND :v_to
GROUP BY SHP_NO
UNION ALL
SELECT '13W', SHP_NO, COUNT(*)
FROM CF10
WHERE SLE_DT BETWEEN :v_w13 AND :v_to
GROUP BY SHP_NO
ORDER BY 1, 2;
-- 조민우가 고친 SQL (4주와 13주가 작게 나온다)
SELECT CASE WHEN SLE_DT >= :v_w1 THEN '01W'
WHEN SLE_DT >= :v_w4 THEN '04W'
ELSE '13W' END AS PRD,
SHP_NO, COUNT(*) AS SLE_CNT
FROM CF10
WHERE SLE_DT BETWEEN :v_w13 AND :v_to
GROUP BY CASE WHEN SLE_DT >= :v_w1 THEN '01W'
WHEN SLE_DT >= :v_w4 THEN '04W'
ELSE '13W' END, SHP_NO
ORDER BY 1, 2;
[원래 SQL]
------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 15 | 00:00:00.29 | 13749 |
| 1 | SORT ORDER BY | | 1 | 15 | 15 | 00:00:00.29 | 13749 |
| 2 | UNION-ALL | | 1 | | 15 | 00:00:00.29 | 13749 |
| 3 | HASH GROUP BY | | 1 | 5 | 5 | 00:00:00.09 | 4583 |
|* 4 | TABLE ACCESS FULL | CF10 | 1 | 4795 | 4862 | 00:00:00.09 | 4583 |
| 5 | HASH GROUP BY | | 1 | 5 | 5 | 00:00:00.10 | 4583 |
|* 6 | TABLE ACCESS FULL | CF10 | 1 | 19180 | 19537 | 00:00:00.10 | 4583 |
| 7 | HASH GROUP BY | | 1 | 5 | 5 | 00:00:00.10 | 4583 |
|* 8 | TABLE ACCESS FULL | CF10 | 1 | 62330 | 63688 | 00:00:00.10 | 4583 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter(("SLE_DT">=:V_W1 AND "SLE_DT"<=:V_TO))
6 - filter(("SLE_DT">=:V_W4 AND "SLE_DT"<=:V_TO))
8 - filter(("SLE_DT">=:V_W13 AND "SLE_DT"<=:V_TO))
[조민우의 SQL] TABLE ACCESS FULL 한 번 · Buffers 4,583
기간별 합계 01W 4,862 · 04W 14,675 · 13W 44,151 (원래 SQL 4,862 · 19,537 · 63,688)
CF10을 한 번만 읽는 SQL을 작성하시오. 행을 복제하는 시점(집계 전인지 뒤인지)에 따라 일량이 어떻게 다른지도 쓰시오.