Skip to content
튜닝 연습인덱스 사용 조건
IDX-056

감사팀 분기 추출이 지난주 배포 뒤로 여섯 배 느려졌다

중급SELECT한빛유통56 / 700

상황 ​

감사팀은 분기마다 「취소 또는 고액 주문」 전체 목록(3년 치, 약 4만 건)을 내려받고, 감사 대시보드도 같은 SQL을 하루 수십 번 호출한다. 원래는 테이블을 한 번 읽고 끝났다. 지난주 조민우가 "OR는 펼쳐야 인덱스를 탄다"는 글을 보고 /*+ USE_CONCAT */ 힌트를 붙였다. 상태 인덱스와 금액 인덱스가 다 있으니 빨라질 거라 생각했는데, 추출 시간이 0.3초에서 1.8초로 늘었다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록(블록당 약 172행) · 주문 순으로 쌓였다
  • ORD_ST COMPLETE 900,000 · PENDING 80,000 · CANCEL 20,000 · ORD_AMT 490,000원 이상 20,512건(2.05%) · 둘 다 해당하는 주문 410건 · 두 조건의 주문은 테이블 전체에 고르게 흩어져 있다
  • 인덱스 IX_ORD_BIG_ST (ORD_ST): 리프 2,775블록 · IX_ORD_BIG_AMT (ORD_AMT): 리프 약 2,780블록 · 통계 최신(ORD_ST 히스토그램 있음)

원본 SQL ​

sql
SELECT /*+ USE_CONCAT */
       ORD_SEQ, CUS_ID, ORD_DT, ORD_ST, ORD_AMT
  FROM T_ORD_BIG
 WHERE ORD_ST = 'CANCEL'
    OR ORD_AMT >= 490000

실행계획 학습용 예시 ​

xplan
-----------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name           | Starts | E-Rows | A-Rows | A-Time      | Buffers |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                |      1 |        |  40102 | 00:00:01.84 |   40433 |
|   1 |  CONCATENATION                |                |      1 |        |  40102 | 00:00:01.84 |   40433 |
|   2 |   TABLE ACCESS BY INDEX ROWID | T_ORD_BIG      |      1 |  20512 |  20512 | 00:00:00.92 |   20421 |
|*  3 |    INDEX RANGE SCAN           | IX_ORD_BIG_AMT |      1 |  20512 |  20512 | 00:00:00.02 |      58 |
|*  4 |   TABLE ACCESS BY INDEX ROWID | T_ORD_BIG      |      1 |  20000 |  19590 | 00:00:00.90 |   20012 |
|*  5 |    INDEX RANGE SCAN           | IX_ORD_BIG_ST  |      1 |  20000 |  20000 | 00:00:00.02 |      59 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("ORD_AMT">=490000)
   4 - filter(LNNVL("ORD_AMT">=490000))
   5 - access("ORD_ST"='CANCEL')

문제 ​

  1. 인덱스 두 개로 갈래마다 찾아갔는데 테이블 전체 스캔보다 일곱 배 가까이 읽은 이유를 갈래마다 숫자로 설명하시오.
  2. 이 추출을 고치시오. OR를 갈래로 펼치는 것이 이득인 경우와 손해인 경우를 갈래가 돌려주는 건수로 구분해 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자