테마
감사팀은 분기마다 「취소 또는 고액 주문」 전체 목록(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 히스토그램 있음)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
-----------------------------------------------------------------------------------------------------------
| 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')