Skip to content
튜닝 연습인덱스 스캔 효율과 테이블 액세스
ACC-049

상품 상세의 상품평 50건을 띄우는 데 상품평 테이블을 거의 통째로 읽는다

기초DDL한빛유통124 / 700

상황 ​

쇼핑몰 상품 상세 화면 아래의 「상품평」 탭은 그 상품의 평가 50건을 최신 순으로 모두 보여 준다. 상세 화면은 하루 약 12만 번 열린다. 상품평 테이블은 48블록짜리 작은 테이블인데, AWR의 'SQL ordered by Gets'에서 이 SQL이 5위에 올라 있다. 조민우가 PK를 타라고 INDEX_DESC 힌트를 넣어 재 보니 오히려 한 블록을 더 읽었다. 아래는 상품 ITM00007이다.

테이블과 인덱스 ​

  • T_ITM_EVL 상품평가: 5,000행 · 48블록(블록당 약 104행) · 컬럼 ITM_ID · EVL_LST_NO · CUS_ID · EVL_DSC(짧은 한 줄 평) · EVL_DT · EVL_PT
  • 상품 100종에 50건씩 · 평가 번호(EVL_LST_NO) 순으로 쌓였고, 평가 번호가 상품 100종을 하나씩 돌아가며 매겨졌다 · 그래서 상품 하나의 50건은 100행 간격으로 떨어져 48블록 가운데 47블록에 하나씩 있다
  • PK_T_ITM_EVL (ITM_ID, EVL_LST_NO): BLEVEL 1 · 리프 15블록 · CLUSTERING_FACTOR 4,700 · 다른 인덱스는 없다 · 통계 최신
  • 새 평가는 하루 수십 건 들어오고, 고치거나 지우는 일은 드물다 · 이 테이블은 상품평 탭과 밤마다 도는 「상품별 평균 평점」 집계가 읽는다

원본 SQL ​

sql
SELECT EVL_LST_NO, CUS_ID, EVL_DT, EVL_PT, EVL_DSC
  FROM T_ITM_EVL
 WHERE ITM_ID = :v_itm
 ORDER BY EVL_LST_NO DESC

실행계획 학습용 예시 · 행이 흩어진 모양은 적재 스크립트 그대로 ​

xplan
[옵티마이저가 고른 계획]
-------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |      1 |        |     50 |00:00:00.01 |      48 |
|   1 |  SORT ORDER BY                |              |      1 |     50 |     50 |00:00:00.01 |      48 |
|*  2 |   TABLE ACCESS FULL           | T_ITM_EVL    |      1 |     50 |     50 |00:00:00.01 |      48 |
-------------------------------------------------------------------------------------------------------
   2 - filter("ITM_ID"=:V_ITM)

[조민우가 /*+ INDEX_DESC(T_ITM_EVL PK_T_ITM_EVL) */ 로 재 본 계획]
-------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |      1 |        |     50 |00:00:00.01 |      49 |
|   1 |  TABLE ACCESS BY INDEX ROWID  | T_ITM_EVL    |      1 |     50 |     50 |00:00:00.01 |      49 |
|*  2 |   INDEX RANGE SCAN DESCENDING | PK_T_ITM_EVL |      1 |     50 |     50 |00:00:00.01 |       2 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ITM_ID"=:V_ITM)

문제 ​

  1. 50건을 보여 주는 데 FULL로는 48블록, PK로는 49블록을 읽는 이유를 행이 쌓인 모양과 CLUSTERING_FACTOR로 설명하시오.
  2. SQL은 그대로 두고 테이블 구조를 바꿔 50건이 몇 블록으로 끝나게 하시오. DDL을 작성하고, 모든 컬럼을 담은 인덱스를 하나 더 만드는 방법과 비교하여 그 구조의 대가를 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자