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

「상품별 현재 판매가」에 상품이 두 줄씩 나온다

중급SELECT유통309 / 700

상황 ​

본사 상품팀의 「상품별 현재 판매가」 화면은 상품 하나에 한 줄이어야 하는데 157줄이 나온다. 48개 상품이 가격 둘(판매가와 매입가처럼 보이는 값)로 두 번씩 나온다. 개발자: "적용일자가 같은 날이라 그렇다. ROWNUM = 1로 하나만 고르면 되지 않나?" 이 SQL은 판매상품(CF11)에 붙는 「정가 기준 매출」 리포트의 인라인 뷰로도 쓰인다.

테이블과 인덱스 ​

  • CF05 상품가격: 157행 · 5블록 · PK CF05_PK (ITM_NO, UPRC_KN_CD, APL_DT) · 적용일자 이력
  • UPRC_KN_CD 단가종류(CF16 공통코드): '10' 판매단가 89행 · '11' 발주단가 68행 · 둘 다 있는 상품 48개 · 판매단가만 41개 · 발주단가만 20개
  • APL_DT VARCHAR2(8): 지금은 157행 전부 '20200101'(첫 적재)이다. 다음 달부터 가격 개정분이 쌓인다.
  • CF01 상품: 109행 · 5블록 · PK ITM_NO · 통계 최신

원본 SQL ​

sql
SELECT a.ITM_NO, i.ITM_NM, a.APL_DT, a.ITM_UPRC
  FROM CF05 a, CF01 i
 WHERE i.ITM_NO = a.ITM_NO
   AND a.APL_DT = (SELECT MAX(b.APL_DT)
                     FROM CF05 b
                    WHERE b.ITM_NO = a.ITM_NO)
 ORDER BY a.ITM_NO

실행계획 학습용 예시 ​

xplan
-------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name    | Starts | E-Rows | A-Rows |    A-Time   | Buffers |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |         |      1 |        |    157 | 00:00:00.01 |      12 |
|   1 |  SORT ORDER BY             |         |      1 |    157 |    157 | 00:00:00.01 |      12 |
|*  2 |   HASH JOIN                |         |      1 |    157 |    157 | 00:00:00.01 |      12 |
|*  3 |    HASH JOIN               |         |      1 |    157 |    157 | 00:00:00.01 |       7 |
|   4 |     VIEW                   | VW_SQ_1 |      1 |    109 |    109 | 00:00:00.01 |       2 |
|   5 |      HASH GROUP BY         |         |      1 |    109 |    109 | 00:00:00.01 |       2 |
|   6 |       INDEX FAST FULL SCAN | CF05_PK |      1 |    157 |    157 | 00:00:00.01 |       2 |
|   7 |     TABLE ACCESS FULL      | CF05    |      1 |    157 |    157 | 00:00:00.01 |       5 |
|   8 |    TABLE ACCESS FULL       | CF01    |      1 |    109 |    109 | 00:00:00.01 |       5 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("I"."ITM_NO"="A"."ITM_NO")
   3 - access("A"."APL_DT"="MAX(B.APL_DT)" AND "ITEM_1"="A"."ITM_NO")

문제 ​

  1. 157줄이 나오는 까닭을 데이터(단가종류, 적용일자)와 실행계획으로 설명하고, 이 SQL이 CF05를 몇 번 읽는지 쓰시오.
  2. 상품마다 현재 판매단가 한 줄이 나오도록 CF05를 한 번만 읽는 SQL로 고치시오.
  3. '같은 상품, 같은 적용일자'인 행이 둘이면 MAX 서브쿼리, ROW_NUMBER, RANK, KEEP (DENSE_RANK LAST)가 각각 무엇을 돌려주는지 설명하고, 하나를 어떻게 정해야 하는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자