Skip to content
튜닝 연습서브쿼리와 쿼리 변환
SUBQ-070

카테고리 평균 대비 칸을 더한 뒤로 상품 판매 분석 화면의 읽기 블록이 두 배가 됐다

기초SELECT유통305 / 700

상황 ​

유통 본사 「상품 판매 분석」 화면은 상품별 6월 판매 수량을 보여 준다. 지난주 상품마다 같은 카테고리 평균과의 비율(%) 칸을 더했는데, 그 뒤로 화면의 읽기 블록이 두 배가 됐다. 개발자는 상품별 집계를 인라인 뷰로 한 번 더 써서 카테고리 평균을 구했다.

테이블과 인덱스 ​

  • CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · 판매번호는 판매일자 8자리로 시작한다 · 2023년 6월 45,935줄
  • CF01 상품: 109행 · 5블록 · CTG_NO 카테고리 · 6월에 팔린 상품 88개(카테고리 12개)
  • 통계 최신

원본 SQL ​

sql
SELECT a.ITM_NO, a.CTG_NO, a.SLE_QTY,
       ROUND(a.SLE_QTY * 100 / b.AVG_QTY, 1) AS VS_CTG_AVG
  FROM (SELECT i.ITM_NO, i.CTG_NO, SUM(s.SLE_QTY) AS SLE_QTY
          FROM CF11 s, CF01 i
         WHERE s.SLE_NO >= '20230601' AND s.SLE_NO < '20230701'
           AND i.ITM_NO = s.ITM_NO
         GROUP BY i.ITM_NO, i.CTG_NO) a,
       (SELECT CTG_NO, AVG(SLE_QTY) AS AVG_QTY
          FROM (SELECT i.ITM_NO, i.CTG_NO, SUM(s.SLE_QTY) AS SLE_QTY
                  FROM CF11 s, CF01 i
                 WHERE s.SLE_NO >= '20230601' AND s.SLE_NO < '20230701'
                   AND i.ITM_NO = s.ITM_NO
                 GROUP BY i.ITM_NO, i.CTG_NO)
         GROUP BY CTG_NO) b
 WHERE b.CTG_NO = a.CTG_NO
 ORDER BY a.CTG_NO, a.ITM_NO

실행계획 학습용 예시 ​

xplan
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                    | Name    | Starts | E-Rows | A-Rows |      A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                             |         |      1 |        |     88 | 00:00:00.10 |    2658 |
|   1 |  SORT ORDER BY                               |         |      1 |     88 |     88 | 00:00:00.10 |    2658 |
|*  2 |   HASH JOIN                                  |         |      1 |     88 |     88 | 00:00:00.10 |    2658 |
|   3 |    VIEW                                      |         |      1 |     12 |     12 | 00:00:00.05 |    1329 |
|   4 |     HASH GROUP BY                            |         |      1 |     12 |     12 | 00:00:00.05 |    1329 |
|   5 |      VIEW                                    |         |      1 |     88 |     88 | 00:00:00.05 |    1329 |
|   6 |       HASH GROUP BY                          |         |      1 |     88 |     88 | 00:00:00.05 |    1329 |
|*  7 |        HASH JOIN                             |         |      1 |  45935 |  45935 | 00:00:00.04 |    1329 |
|   8 |         TABLE ACCESS FULL                    | CF01    |      1 |    109 |    109 | 00:00:00.01 |       5 |
|   9 |         TABLE ACCESS BY INDEX ROWID BATCHED  | CF11    |      1 |  45935 |  45935 | 00:00:00.02 |    1324 |
|* 10 |          INDEX RANGE SCAN                    | CF11_PK |      1 |  45935 |  45935 | 00:00:00.01 |     176 |
|  11 |    VIEW                                      |         |      1 |     88 |     88 | 00:00:00.05 |    1329 |
|  12 |     HASH GROUP BY                            |         |      1 |     88 |     88 | 00:00:00.05 |    1329 |
|* 13 |      HASH JOIN                               |         |      1 |  45935 |  45935 | 00:00:00.04 |    1329 |
|  14 |       TABLE ACCESS FULL                      | CF01    |      1 |    109 |    109 | 00:00:00.01 |       5 |
|  15 |       TABLE ACCESS BY INDEX ROWID BATCHED    | CF11    |      1 |  45935 |  45935 | 00:00:00.02 |    1324 |
|* 16 |        INDEX RANGE SCAN                      | CF11_PK |      1 |  45935 |  45935 | 00:00:00.01 |     176 |
-------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("B"."CTG_NO"="A"."CTG_NO")
   7 - access("I"."ITM_NO"="S"."ITM_NO")
  10 - access("S"."SLE_NO">='20230601' AND "S"."SLE_NO"<'20230701')
  13 - access("I"."ITM_NO"="S"."ITM_NO")
  16 - access("S"."SLE_NO">='20230601' AND "S"."SLE_NO"<'20230701')

문제 ​

  1. 읽기 블록이 두 배가 된 이유를 실행계획의 줄 번호와 Buffers로 설명하시오.
  2. 결과가 바뀌지 않게 상품별 집계를 한 번만 하도록 SQL을 고치시오. 다른 방법이 있다면 함께 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자