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

클레임 주문 한 건을 찾으려고 만든 인덱스가 기존 인덱스보다 세 배를 읽는다

기초DDL버거83 / 700

상황 ​

버거원 고객센터는 "SH0123 매장에서 11월 2일 저녁 6시쯤 주문했는데 음식이 잘못 나왔다" 같은 클레임을 받으면, 매장과 날짜, 시각 앞뒤 30분으로 주문을 찾는다. 하루에 수백 번 조회한다. 조민우가 이 조회를 위해 인덱스를 설계했다. 메모에는 "선택도가 좋은 순서로: ORD_HMS 50,400종, ORD_DT 730종, SHOP_NO 200종"이라고 적었다. INVISIBLE로 만들어 세션에서 재 보니 기존 인덱스보다 세 배를 읽었다.

테이블과 인덱스 ​

  • ORD_RANDOM(운영본): 1,000,000행 · 22,414블록 · 무작위 순서로 적재
  • ORD_DT VARCHAR2(8) 2012 ~ 2013(730일) · ORD_HMS VARCHAR2(6) '090000' ~ '225959'에 고르게 분포(한 시간에 약 7.1%) · SHOP_NO 200개 매장 · 매장 하나의 하루 주문은 평균 6.8건
  • 인덱스 ORD_RANDOM_PK (ORD_NO) · ORD_RANDOM_X01 (ORD_DT, ORD_HMS): BLEVEL 2 · 리프 3,774 · CLUSTERING_FACTOR 999,958
  • 조민우 안 ORD_RANDOM_X09 (ORD_HMS, ORD_DT, SHOP_NO): INVISIBLE · BLEVEL 2 · 리프 약 4,350블록(리프 한 블록에 약 230항목)

원본 SQL ​

sql
SELECT ORD_NO, ORD_HMS
  FROM ORD_RANDOM
 WHERE SHOP_NO = :v_shop
   AND ORD_DT  = :v_dt
   AND ORD_HMS BETWEEN :v_hms_from AND :v_hms_to
 ORDER BY ORD_HMS;

-- 조민우 안
CREATE INDEX ORD_RANDOM_X09 ON ORD_RANDOM (ORD_HMS, ORD_DT, SHOP_NO) INVISIBLE;

실행계획 학습용 예시 · 인덱스 규모는 교재 04화 실측 ​

xplan
[지금 — ORD_RANDOM_X01 · SH0123 · '20131102' · '173000' ~ '183000']
-----------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                |      1 |        |      1 |00:00:00.01 |     100 |
|   1 |  SORT ORDER BY                        |                |      1 |      1 |      1 |00:00:00.01 |     100 |
|*  2 |   FILTER                              |                |      1 |        |      1 |00:00:00.01 |     100 |
|*  3 |    TABLE ACCESS BY INDEX ROWID BATCHED| ORD_RANDOM     |      1 |      1 |      1 |00:00:00.01 |     100 |
|*  4 |     INDEX RANGE SCAN                  | ORD_RANDOM_X01 |      1 |     98 |     99 |00:00:00.01 |       3 |
-----------------------------------------------------------------------------------------------------------------
   2 - filter(:V_HMS_FROM<=:V_HMS_TO)
   3 - filter("SHOP_NO"=:V_SHOP)
   4 - access("ORD_DT"=:V_DT AND "ORD_HMS">=:V_HMS_FROM AND "ORD_HMS"<=:V_HMS_TO)

[조민우 안 — ORD_RANDOM_X09 · 세션에서만 VISIBLE · 같은 값]
-----------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                |      1 |        |      1 |00:00:00.02 |     314 |
|*  1 |  FILTER                               |                |      1 |        |      1 |00:00:00.02 |     314 |
|   2 |   TABLE ACCESS BY INDEX ROWID         | ORD_RANDOM     |      1 |      1 |      1 |00:00:00.02 |     314 |
|*  3 |    INDEX RANGE SCAN                   | ORD_RANDOM_X09 |      1 |      1 |      1 |00:00:00.02 |     313 |
-----------------------------------------------------------------------------------------------------------------
   1 - filter(:V_HMS_FROM<=:V_HMS_TO)
   3 - access("ORD_HMS">=:V_HMS_FROM AND "ORD_DT"=:V_DT AND "SHOP_NO"=:V_SHOP AND "ORD_HMS"<=:V_HMS_TO)
       filter(("ORD_DT"=:V_DT AND "SHOP_NO"=:V_SHOP))

문제 ​

  1. 조민우 안의 3번 줄이 313블록을 읽는 이유를 access와 filter로 설명하시오. 메모의 기준이 왜 틀렸는지도 설명하시오.
  2. 이 조회에 맞는 인덱스를 설계해 DDL을 작성하시오. = 조건 컬럼 둘의 순서는 무엇으로 정하는지도 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자