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

상담원 주문 검색이 고객번호를 넣어도 석 달 치 주문을 다 읽는다

중급SELECT한빛유통54 / 700

상황 ​

고객센터 「주문 검색」은 기간을 반드시 넣고, 주문번호와 고객번호 가운데 아는 것을 더 넣어 찾는다. 상담원 40명이 하루 약 1만 번 쓰고, 열에 아홉은 고객번호와 석 달 기간을 넣는다. 둘 다 비우면 화면이 기간을 하루로 묶는다. SQL은 한 문장이고, 넣지 않은 칸을 건너뛰려고 조건마다 (:v IS NULL OR ...)를 달았다. 오과장은 "고객번호로 시작하는 인덱스까지 만들어 줬는데 왜 안 쓰느냐"고 묻는다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_SEQ 유일 · CUS_ID NOT NULL(2,000명, 고객당 500건, 테이블 전체에 흩어져 있다) · ORD_DT DATE(전부 자정, 하루 913건, 석 달 약 8만 3천 건)
  • 인덱스 IX_ORD_BIG_SEQ (ORD_SEQ) 유니크 · IX_ORD_BIG_CUS_DT (CUS_ID, ORD_DT) · IX_ORD_BIG_DT (ORD_DT) · 통계 최신
  • 고객 CUS_000123의 2024-04-01 ~ 2024-06-30 주문 41건

원본 SQL ​

sql
SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_ST, ORD_AMT
  FROM T_ORD_BIG
 WHERE ORD_DT >= TO_DATE(:v_from, 'YYYYMMDD')
   AND ORD_DT <  TO_DATE(:v_to, 'YYYYMMDD') + 1
   AND (:v_ord IS NULL OR ORD_SEQ = :v_ord)
   AND (:v_cus IS NULL OR CUS_ID = :v_cus)
 ORDER BY ORD_DT DESC, ORD_SEQ DESC

실행계획 학습용 예시 ​

xplan
[고객번호 CUS_000123 · 2024-04-01 ~ 2024-06-30]
---------------------------------------------------------------------------------------------
| Id  | Operation            | Name      | Starts | E-Rows | A-Rows | A-Time      | Buffers |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |           |      1 |        |     41 | 00:00:00.09 |    5826 |
|   1 |  SORT ORDER BY       |           |      1 |    205 |     41 | 00:00:00.09 |    5826 |
|*  2 |   FILTER             |           |      1 |        |     41 | 00:00:00.09 |    5826 |
|*  3 |    TABLE ACCESS FULL | T_ORD_BIG |      1 |    205 |     41 | 00:00:00.09 |    5826 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_DATE(:V_TO,'YYYYMMDD')+1>TO_DATE(:V_FROM,'YYYYMMDD'))
   3 - filter(("ORD_DT">=TO_DATE(:V_FROM,'YYYYMMDD') AND "ORD_DT"<TO_DATE(:V_TO,'YYYYMMDD')+1 AND
              (:V_ORD IS NULL OR "ORD_SEQ"=:V_ORD) AND (:V_CUS IS NULL OR "CUS_ID"=:V_CUS)))

문제 ​

  1. 고객번호를 넣었는데도 IX_ORD_BIG_CUS_DT를 쓰지 못하고 테이블 전체를 읽는 이유를 Predicate Information으로 설명하시오.
  2. 입력 조합(주문번호가 있을 때, 고객번호만 있을 때, 기간만 있을 때)마다 맞는 인덱스로 찾아가도록 SQL을 고치시오.
  3. 고친 방법의 대가와, 옵션 조건이 더 늘어날 때의 대안을 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자