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

새 인덱스로 상품 일 판매는 빨라졌는데 월간 추이는 345블록을 읽는다

중급DDL버거86 / 700

상황 ​

버거원 상품기획팀은 두 화면을 쓴다. 「상품 일 판매」는 날짜와 상품 하나를 골라 판매 수량을 보고, 「상품 월간 추이」는 상품 하나의 한 달 일별 판매 수량을 그린다. 둘 다 하루 수백 번 연다. 조민우가 두 화면을 위한 인덱스 요청서를 올렸다. "(ORD_DT, ITEM_ID, ORD_ITEM_QTY). ORD_DT는 730종, ITEM_ID는 92종이므로 선택도가 좋은 ORD_DT를 앞에 둔다." INVISIBLE로 만들어 재 보니 일 판매는 4블록인데 월간 추이는 345블록이다.

테이블과 인덱스 ​

  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · 주문 날짜순으로 적재 · ITEM_ID 1 ~ 92에 고르게 분포(상품당 약 26,900행, 하루 약 37행) · ORD_DT VARCHAR2(8) 2012 ~ 2013 · 2013년 11월 약 102,900행
  • 자이언트더블버거 ITEM_ID = 84: 2013년 11월 1,121행
  • 인덱스 ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS)(CF 좋음)
  • 조민우 안 ORD_ITEM_X02 (ORD_DT, ITEM_ID, ORD_ITEM_QTY): INVISIBLE · BLEVEL 2 · 리프 약 8,500블록(리프 한 블록에 약 290항목)

원본 SQL ​

sql
-- S1 「상품 일 판매」
SELECT SUM(ORD_ITEM_QTY) AS qty, COUNT(*) AS line_cnt
  FROM ORD_ITEM
 WHERE ORD_DT  = :v_dt
   AND ITEM_ID = :v_item;

-- S2 「상품 월간 추이」
SELECT ORD_DT, SUM(ORD_ITEM_QTY) AS qty
  FROM ORD_ITEM
 WHERE ITEM_ID = :v_item
   AND ORD_DT BETWEEN :v_from AND :v_to
 GROUP BY ORD_DT
 ORDER BY ORD_DT;

-- 요청서
CREATE INDEX ORD_ITEM_X02 ON ORD_ITEM (ORD_DT, ITEM_ID, ORD_ITEM_QTY) INVISIBLE;

실행계획 학습용 예시 · 규모는 schemas 그대로 ​

xplan
[지금 — 요청서 인덱스 없이] S1 ORD_ITEM_X01 + 테이블에서 상품을 거른다 91 · S2 ORD_ITEM_X01 + 테이블 2,648

[요청서 X02 · 세션에서만 — S1 (2013-11-02, 상품 84)]
-----------------------------------------------------------------------------------------------
| Id  | Operation          | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |              |      1 |        |      1 |00:00:00.01 |       4 |
|   1 |  SORT AGGREGATE    |              |      1 |      1 |      1 |00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN | ORD_ITEM_X02 |      1 |     37 |     38 |00:00:00.01 |       4 |
-----------------------------------------------------------------------------------------------
   2 - access("ORD_DT"=:V_DT AND "ITEM_ID"=:V_ITEM)

[요청서 X02 · 세션에서만 — S2 (2013년 11월, 상품 84)]
-----------------------------------------------------------------------------------------------
| Id  | Operation          | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |              |      1 |        |     30 |00:00:00.02 |     345 |
|   1 |  SORT GROUP BY NOSORT|            |      1 |     41 |     30 |00:00:00.02 |     345 |
|*  2 |   FILTER           |              |      1 |        |   1121 |00:00:00.02 |     345 |
|*  3 |    INDEX RANGE SCAN| ORD_ITEM_X02 |      1 |     41 |   1121 |00:00:00.02 |     345 |
-----------------------------------------------------------------------------------------------
   2 - filter(:V_FROM<=:V_TO)
   3 - access("ORD_DT">=:V_FROM AND "ITEM_ID"=:V_ITEM AND "ORD_DT"<=:V_TO)
       filter("ITEM_ID"=:V_ITEM)

문제 ​

  1. S1은 어느 순서로 만들어도 같은 양을 읽는데 S2는 그렇지 않은 이유를 access와 filter로 설명하시오.
  2. 두 화면에 맞는 인덱스를 설계해 DDL을 작성하시오. 요청서의 근거('선택도가 좋은 컬럼을 앞에')가 왜 틀렸는지 설명하고, 그 인덱스의 대가도 적으시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자