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

속도 개선 배포 뒤로 「전체」를 고르면 결제 대기 주문이 목록에서 사라진다

중급SELECT한빛유통58 / 700

상황 ​

정산팀 「일별 주문 목록」은 주문일(필수)과 결제수단(옵션, 기본값 「전체」)으로 조회한다. 지난주 조민우가 "OR가 있으면 인덱스를 못 탄다"며 결제수단 조건을 NVL로 바꿔 배포했다. 그 뒤로 「전체」로 보면 결제 대기 주문이 빠진다는 문의가 들어왔다. 화면 속도는 배포 전과 달라진 게 없다고 한다.

테이블과 인덱스 ​

  • T_ORD 주문: 100,000행 · 896블록 · 주문 순으로 쌓였다 · ORD_DT DATE(시분초 있음, 하루 136 ~ 137건) · PAY_TP 결제수단(CARD 70% · BANK 20% · PHONE 7% · POINT 3%, 결제 전이면 NULL) · PAY_DT · ORD_AMT
  • 인덱스 IX_T_ORD_DT (ORD_DT): BLEVEL 1 · 통계 최신 · PAY_TP에는 인덱스가 없다
  • 2024-12-30 주문 137건 가운데 결제 대기(PAY_TP NULL) 9건

원본 SQL ​

sql
-- [배포 전]
SELECT ORD_SEQ, CUS_ID, ORD_DT, PAY_TP, ORD_AMT
  FROM T_ORD
 WHERE ORD_DT >= TO_DATE(:v_dt, 'YYYYMMDD')
   AND ORD_DT <  TO_DATE(:v_dt, 'YYYYMMDD') + 1
   AND (:v_tp IS NULL OR PAY_TP = :v_tp)
 ORDER BY ORD_DT;

-- [배포 후] 조민우
SELECT ORD_SEQ, CUS_ID, ORD_DT, PAY_TP, ORD_AMT
  FROM T_ORD
 WHERE ORD_DT >= TO_DATE(:v_dt, 'YYYYMMDD')
   AND ORD_DT <  TO_DATE(:v_dt, 'YYYYMMDD') + 1
   AND PAY_TP = NVL(:v_tp, PAY_TP)
 ORDER BY ORD_DT;

실행계획 학습용 예시 ​

xplan
[배포 전 · 2024-12-30 · 「전체」(:v_tp NULL)]
-------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows | A-Rows | A-Time      | Buffers |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |    137 | 00:00:00.01 |       4 |
|*  1 |  TABLE ACCESS BY INDEX ROWID | T_ORD       |      1 |    137 |    137 | 00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN           | IX_T_ORD_DT |      1 |    137 |    137 | 00:00:00.01 |       2 |
-------------------------------------------------------------------------------------------------------
   1 - filter((:V_TP IS NULL OR "PAY_TP"=:V_TP))
   2 - access("ORD_DT">=TO_DATE(:V_DT,'YYYYMMDD') AND "ORD_DT"<TO_DATE(:V_DT,'YYYYMMDD')+1)

[배포 후 · 같은 날 · 「전체」]
-------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows | A-Rows | A-Time      | Buffers |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |    128 | 00:00:00.01 |       4 |
|*  1 |  TABLE ACCESS BY INDEX ROWID | T_ORD       |      1 |    137 |    128 | 00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN           | IX_T_ORD_DT |      1 |    137 |    137 | 00:00:00.01 |       2 |
-------------------------------------------------------------------------------------------------------
   1 - filter("PAY_TP"=NVL(:V_TP,"PAY_TP"))
   2 - access("ORD_DT">=TO_DATE(:V_DT,'YYYYMMDD') AND "ORD_DT"<TO_DATE(:V_DT,'YYYYMMDD')+1)

문제 ​

  1. 배포 전 SQL의 OR가 인덱스 사용을 막고 있었는지 두 실행계획으로 판정하시오.
  2. 「전체」에서 결제 대기 9건이 빠지는 이유를 설명하고, 결과도 계획도 맞도록 SQL을 고치시오.
  3. col = NVL(:v, col) 모양을 써도 되는 컬럼과 안 되는 컬럼을 구분하고, 옵션 조건을 갈래로 나눌 가치가 있는 경우를 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자