Skip to content
튜닝 연습조인 튜닝
JOIN-007

쉐이크 네 가지의 12월 판매 건수를 세는데 판매상품 인덱스를 네 번 훑는다

기초SELECT유통157 / 700

상황 ​

상품팀의 「카테고리 월 판매 건수」 화면은 카테고리를 고르면 그 카테고리의 상품마다 한 달 동안 팔린 줄 수를 보여 준다. 카테고리와 달을 바꿔 가며 하루 3천 번쯤 호출된다. 개발자는 "NL 조인이라 인덱스를 타니까 빠를 줄 알았다"라고 한다. 아래는 쉐이크(CTG_NO = 112, 상품 4개)의 2023년 12월을 조회한 실행계획이다.

테이블과 인덱스 ​

  • CF01 상품: 109행 · 5블록 · CF01_PK (ITM_NO) · 쉐이크 카테고리 상품 4개 (ITM_NO 1030 ~ 1033)
  • CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) 리프 약 4,300블록 · SLE_NO는 'YYYYMMDD-NNNN' 모양
  • 2023년 12월 판매상품 46,322줄 (CF11_PK 리프 약 181블록) · 그중 쉐이크 4종은 548줄 (129 · 135 · 138 · 146줄)
  • 보조 인덱스 없음 · 통계 최신 · 바인드 :v_from = '20231201', :v_to = '20240101'

원본 SQL ​

sql
SELECT /*+ LEADING(p) USE_NL(i) */
       p.ITM_NO, p.ITM_NM, COUNT(*) AS sle_lines
  FROM CF01 p, CF11 i
 WHERE p.CTG_NO = :ctg
   AND i.ITM_NO = p.ITM_NO
   AND i.SLE_NO >= :v_from
   AND i.SLE_NO <  :v_to
 GROUP BY p.ITM_NO, p.ITM_NM

실행계획 학습용 예시 · 행 수는 실데이터 ​

xplan
-------------------------------------------------------------------------------------------
| Id  | Operation             | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |         |      1 |        |      4 |00:00:00.02 |     737 |
|   1 |  HASH GROUP BY        |         |      1 |      8 |      4 |00:00:00.02 |     737 |
|*  2 |   FILTER              |         |      1 |        |    548 |00:00:00.02 |     737 |
|   3 |    NESTED LOOPS       |         |      1 |   4184 |    548 |00:00:00.02 |     737 |
|*  4 |     TABLE ACCESS FULL | CF01    |      1 |      8 |      4 |00:00:00.01 |       5 |
|*  5 |     INDEX RANGE SCAN  | CF11_PK |      4 |    523 |    548 |00:00:00.02 |     732 |
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(:V_FROM<:V_TO)
   4 - filter("P"."CTG_NO"=:CTG)
   5 - access("I"."SLE_NO">=:V_FROM AND "I"."ITM_NO"="P"."ITM_NO" AND "I"."SLE_NO"<:V_TO)
       filter("I"."ITM_NO"="P"."ITM_NO")

문제 ​

  1. 5번 줄의 Starts와 Buffers를 보고, 상품 하나를 찾을 때마다 인덱스를 얼마나 읽는지 설명하시오. Predicate Information 5번에 조인 조건이 access와 filter에 모두 나오는 이유도 설명하시오.
  2. 상품마다 그 상품의 그달 판매 줄만 읽도록 인덱스를 설계하고 SQL을 작성하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자