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

인덱스 힌트까지 넣었는데 결제 모니터의 한 시간치 조회가 인덱스를 처음부터 끝까지 읽는다

중급SELECT한빛유통23 / 700

상황 ​

결제팀의 「결제 대기 모니터」는 10분마다 직전 한 시간의 주문을 뽑아 결제 상태를 확인한다. 결제팀 화면 여섯 대가 띄워 두고 있어 하루 860번쯤 돈다. 지난주 조민우가 ORD_DT에 인덱스를 만들었는데 계획은 그대로 FULL이었다. 그래서 INDEX 힌트를 넣었더니 이번에는 인덱스를 처음부터 끝까지 읽는다. 자바 코드는 기간을 java.sql.Timestamp로 만들어 ps.setTimestamp로 넘긴다.

테이블과 인덱스 ​

  • T_ORD 주문: 100,000행 · 896블록 · ORD_DT DATE(시분초 있음, 2023-01-01 ~ 2024-12-31) · 한 시간에 약 6건 · PAY_DT · PAY_AMT
  • 인덱스 PK_T_ORD (ORD_SEQ) · IX_T_ORD_DT (ORD_DT): 지난주 생성 · BLEVEL 1 · 리프 265블록 · 통계 최신
  • 같은 날짜의 주문은 테이블 곳곳에 흩어져 있다(주문 6건이면 테이블 블록 6개)

원본 SQL ​

sql
-- [원본]
SELECT ORD_SEQ, CUS_ID, ORD_DT, PAY_DT, PAY_AMT
  FROM T_ORD
 WHERE ORD_DT >= :1
   AND ORD_DT <  :2
 ORDER BY ORD_DT;

-- [조민우의 시도]
SELECT /*+ INDEX(T_ORD IX_T_ORD_DT) */
       ORD_SEQ, CUS_ID, ORD_DT, PAY_DT, PAY_AMT
  FROM T_ORD
 WHERE ORD_DT >= :1
   AND ORD_DT <  :2
 ORDER BY ORD_DT;

실행계획 학습용 예시 ​

xplan
[원본 · 2024-06-14 09:00 ~ 10:00]
--------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |      1 |        |      6 |00:00:00.02 |     896 |
|   1 |  SORT ORDER BY              |             |      1 |    250 |      6 |00:00:00.02 |     896 |
|*  2 |   TABLE ACCESS FULL         | T_ORD       |      1 |    250 |      6 |00:00:00.02 |     896 |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter((INTERNAL_FUNCTION("ORD_DT")>=:1 AND INTERNAL_FUNCTION("ORD_DT")<:2))

[조민우의 시도 · INDEX 힌트]
--------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |      1 |        |      6 |00:00:00.03 |     272 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_ORD       |      1 |    250 |      6 |00:00:00.03 |     272 |
|*  2 |   INDEX FULL SCAN           | IX_T_ORD_DT |      1 |    250 |      6 |00:00:00.03 |     266 |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter((INTERNAL_FUNCTION("ORD_DT")>=:1 AND INTERNAL_FUNCTION("ORD_DT")<:2))

[V$SQL_BIND_CAPTURE]
NAME  DATATYPE_STRING  VALUE_STRING
----  ---------------  -----------------------------
:1    TIMESTAMP        2024-06-14 09:00:00.000000000
:2    TIMESTAMP        2024-06-14 10:00:00.000000000

문제 ​

  1. Predicate Information의 INTERNAL_FUNCTION("ORD_DT")가 무엇을 뜻하는지, 왜 컬럼 쪽에 붙었는지 바인드 정보로 설명하시오.
  2. 힌트를 넣은 판이 INDEX RANGE SCAN이 아니라 INDEX FULL SCAN이 된 이유를 설명하시오.
  3. 한 시간 범위만 읽도록 SQL을 고치고, 자바 쪽에서 고칠 때 주의할 점을 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자