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

영수증 한 장의 품목 조회는 판매상품을 통째로 읽는데, 상품명을 붙인 조회는 바로 뜬다

중급DDL유통288 / 700

상황 ​

매장 관리 화면에는 영수증 번호로 여는 화면이 둘 있다. [가] 「영수증 품목」은 한 번에 0.06초, [나] 「영수증 품목 · 상품명」은 0.001초다. 둘 다 공통 뷰 V_SLE_ITM을 읽고, 점장들이 합쳐서 하루 수천 번 연다. 이 뷰는 2019년 야간 상품 매출 리포트용으로 만들었다. 그해 통계가 비어 있던 날 리포트가 인덱스로 판매상품을 다 읽어 30분이 걸렸고, 그 뒤 뷰 정의에 FULL(d) 힌트를 넣었다. 개발자는 "[나]도 같은 뷰인데 왜 [가]만 힌트가 먹느냐"고 묻는다.

테이블과 인덱스 ​

  • CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) 높이 3 · 영수증 한 장에 평균 2.2줄(한 블록 안)
  • CF01 상품: 109행 · 5블록 · CF01_PK (ITM_NO)
  • 야간 리포트는 한 달 치 판매상품(약 45,000줄)을 상품별로 묶는다 · 통계 최신

원본 SQL ​

sql
-- 공통 뷰 (2019년 야간 리포트 사고 뒤 힌트를 넣었다)
CREATE OR REPLACE VIEW V_SLE_ITM AS
SELECT /*+ FULL(d) */
       d.SLE_NO, d.ITM_NO, d.SLE_QTY, d.SLE_UPRC,
       d.SLE_QTY * d.SLE_UPRC AS SLE_AMT
  FROM CF11 d;

-- [가] 영수증 품목 (0.06초)
SELECT ITM_NO, SLE_QTY, SLE_AMT
  FROM V_SLE_ITM
 WHERE SLE_NO = :sle_no;

-- [나] 영수증 품목 · 상품명 (0.001초)
SELECT v.ITM_NO, i.ITM_NM, v.SLE_QTY, v.SLE_AMT
  FROM V_SLE_ITM v, CF01 i
 WHERE v.SLE_NO = :sle_no
   AND i.ITM_NO = v.ITM_NO;

실행계획 학습용 예시 ​

xplan
[가]
-----------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |      3 |00:00:00.06 |    8204 |
|*  1 |  TABLE ACCESS FULL| CF11 |      1 |      2 |      3 |00:00:00.06 |    8204 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("D"."SLE_NO"=:SLE_NO)

[나]
---------------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |      1 |        |      3 |00:00:00.01 |      10 |
|   1 |  NESTED LOOPS                |         |      1 |      2 |      3 |00:00:00.01 |      10 |
|   2 |   NESTED LOOPS               |         |      1 |      2 |      3 |00:00:00.01 |       7 |
|   3 |    TABLE ACCESS BY INDEX ROWID| CF11   |      1 |      2 |      3 |00:00:00.01 |       4 |
|*  4 |     INDEX RANGE SCAN         | CF11_PK |      1 |      2 |      3 |00:00:00.01 |       3 |
|*  5 |    INDEX UNIQUE SCAN         | CF01_PK |      3 |      1 |      3 |00:00:00.01 |       3 |
|   6 |   TABLE ACCESS BY INDEX ROWID| CF01    |      3 |      1 |      3 |00:00:00.01 |       3 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   4 - access("D"."SLE_NO"=:SLE_NO)
   5 - access("I"."ITM_NO"="D"."ITM_NO")

문제 ​

  1. 두 화면 모두 계획에 VIEW 줄이 없는 이유와, 같은 뷰의 FULL(d) 힌트가 [가]에서는 지켜지고 [나]에서는 지켜지지 않은 이유를 설명하시오.
  2. [가]가 영수증 한 장만 읽도록 고치시오. 야간 리포트가 2019년처럼 흔들리지 않게 하려면 힌트를 어디에 두어야 하는지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자