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

일 마감 화면의 하루 매출 조회에 SKIP SCAN이 보인다며 날짜 인덱스를 따로 만들자고 한다

기초SELECT이커머스111 / 700

이 문제는 교재 18화 졸업 과제와 같은 이커머스 데이터베이스를 씁니다. 『튜너의 1년』을 순서대로 읽고 있다면 졸업 과제를 먼저 풀고 오세요. 아래 「테이블과 인덱스」 칸에 과제의 답 일부(제약 조건, 인덱스, 통계의 실제 상태)가 나옵니다.

상황 ​

운영팀의 「일 마감」 화면은 날짜 하나를 고르면 그날의 주문 건수와 매출 합계를 보여 준다. 마감 담당자들이 하루 200번쯤 연다. 실행계획을 본 조민우가 이렇게 말했다. "INDEX SKIP SCAN이 보인다. SKIP SCAN은 선두 컬럼을 빠뜨렸을 때 나오는 나쁜 신호라고 배웠다(IDX-006). 매출까지 담은 (order_date, total_amount) 인덱스를 따로 만들자." 아래는 2024년 6월 14일을 골랐을 때다.

테이블과 인덱스 ​

  • orders: 34,908행 · 193블록 · order_date DATE(시분초 있음, 2020 ~ 2024, 하루 약 20건) · status 6종 · 2024-06-14 주문 19건
  • 인덱스 PK_ORDERS (order_id) · IX_ORD_CUST_DT (customer_id, order_date) · IX_ORD_ST_DT (status, order_date, total_amount): 뒤의 둘은 ACC-005에서 만든 인덱스다 · IX_ORD_ST_DT는 BLEVEL 1 · 리프 약 150블록(상태 하나에 약 25블록) · 통계 최신
  • 인덱스가 하나 늘면 주문 INSERT마다 고칠 인덱스가 넷이 된다 · 참고(교재 18화 실측): orders 34,908행을 적재할 때 인덱스 하나가 redo를 약 1.56 → 12.1MB로 늘린다

원본 SQL ​

sql
SELECT COUNT(*) AS ord_cnt, SUM(total_amount) AS amt
  FROM orders
 WHERE order_date >= TO_DATE(:v_dt, 'YYYYMMDD')
   AND order_date <  TO_DATE(:v_dt, 'YYYYMMDD') + 1

실행계획 학습용 예시 · 인덱스는 ACC-005의 처방 · 적재 비용은 교재 18화 실측 ​

xplan
---------------------------------------------------------------------------------------------
| Id  | Operation          | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |              |      1 |        |      1 |00:00:00.01 |      13 |
|   1 |  SORT AGGREGATE    |              |      1 |      1 |      1 |00:00:00.01 |      13 |
|*  2 |   FILTER           |              |      1 |        |     19 |00:00:00.01 |      13 |
|*  3 |    INDEX SKIP SCAN | IX_ORD_ST_DT |      1 |     19 |     19 |00:00:00.01 |      13 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_DATE(:V_DT,'YYYYMMDD')+1>TO_DATE(:V_DT,'YYYYMMDD'))
   3 - access("ORDER_DATE">=TO_DATE(:V_DT,'YYYYMMDD') AND "ORDER_DATE"<TO_DATE(:V_DT,'YYYYMMDD')+1)
       filter(("ORDER_DATE">=TO_DATE(:V_DT,'YYYYMMDD') AND "ORDER_DATE"<TO_DATE(:V_DT,'YYYYMMDD')+1))

[같은 조건 · FULL 강제] 193

문제 ​

  1. 3번 줄의 INDEX SKIP SCAN이 13블록만 읽은 이유를 IX_ORD_ST_DT의 선두 컬럼 분포로 설명하시오. IDX-006에서 SKIP SCAN이 오히려 더 많이 읽었던 경우와 무엇이 다른지도 설명하시오.
  2. 조민우의 제안을 받아들일지 숫자로 판단하시오. SKIP SCAN에 맡겨 둘 때 무엇이 바뀌면 다시 재 봐야 하는지도 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자