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

주문 시각 인덱스가 있는데도 매시 정산 연계가 주문 테이블을 통째로 읽는다

기초SELECT한빛유통49 / 700

상황 ​

한빛유통의 정산 시스템은 매시 정각에 지난 한 시간의 변경분을 받아 간다. 그 한 시간에 새로 들어온 주문과 결제가 끝난 주문이 변경분이고, 둘 중 하나에만 걸려도 보낸다. 연계 SQL은 한 문장이다. 조민우는 이렇게 말한다. "ORD_DT에 인덱스가 있는데 FULL로 돈다. OR라서 그런 것 같으니 UNION ALL로 나눠 보겠다." 아래는 2024-12-30 14:00 ~ 15:00 구간을 넘겼을 때의 실행계획이다.

테이블과 인덱스 ​

  • T_ORD 주문: 100,000행 · 896블록 · 주문 순으로 쌓였다 · ORD_DT DATE(주문 시각, 시분초 있음, NOT NULL, 한 시간에 약 6건) · PAY_DT DATE(결제 시각, 주문 뒤 몇 분 ~ 이틀 안, 결제 전이면 NULL) · CUS_ID · ORD_ST · PAY_AMT
  • 인덱스 PK_T_ORD (ORD_SEQ) · IX_T_ORD_DT (ORD_DT): BLEVEL 1 · 통계 최신 · PAY_DT에는 인덱스가 없다
  • 2024-12-30 14시대: 이 시간에 들어온 주문 6건, 이 시간에 결제된 주문 7건, 그중 4건은 이 시간에 주문하고 결제까지 끝냈다(변경분 9건)
  • 연계는 구간의 시작과 끝을 DATE 바인드(:v_from, :v_to)로 넘긴다

원본 SQL ​

sql
SELECT ORD_SEQ, CUS_ID, ORD_DT, PAY_DT, ORD_ST, PAY_AMT
  FROM T_ORD
 WHERE (ORD_DT >= :v_from AND ORD_DT < :v_to)
    OR (PAY_DT >= :v_from AND PAY_DT < :v_to)

실행계획 학습용 예시 ​

xplan
---------------------------------------------------------------------------------------
| Id  | Operation          | Name  | Starts | E-Rows | A-Rows | A-Time      | Buffers |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |      1 |        |      9 | 00:00:00.01 |     896 |
|*  1 |  TABLE ACCESS FULL | T_ORD |      1 |     12 |      9 | 00:00:00.01 |     896 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter((("ORD_DT">=:V_FROM AND "ORD_DT"<:V_TO) OR ("PAY_DT">=:V_FROM AND "PAY_DT"<:V_TO)))

문제 ​

  1. IX_T_ORD_DT가 있는데도 1번 줄이 TABLE ACCESS FULL인 이유를 OR의 두 갈래로 나눠 설명하시오.
  2. 결과를 바꾸지 않고 변경분만 인덱스로 찾아가도록 DDL과 SQL을 작성하시오. 조민우처럼 SQL 두 개를 UNION ALL로 이어 붙일 때 주의할 점도 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자