Skip to content
튜닝 연습소트 튜닝과 페이징
SORT-014

인덱스 이름을 표준에 맞춘 다음 날부터 「재구매 간격」이 전부 수백 일로 나온다

기초SELECT한빛유통319 / 700

상황 ​

고객센터 주문 상세 화면 위쪽에는 「재구매 간격」(이번 주문일과 직전 주문일 사이의 날짜 수)이 있다. 지난 토요일 DBA가 인덱스 이름을 명명 표준(IX_테이블_컬럼)에 맞춰 정리했다. ALTER INDEX T_ORD_BIG_X02 RENAME TO IX_ORD_BIG_CUS_DT처럼 이름만 바꾼 작업이라 영향 검토는 하지 않았다. 월요일 아침부터 상담원들이 "재구매 간격이 전부 700일, 900일로 나온다"라고 한다. 직전 주문일을 구하는 SQL은 2019년에 강도현이 쓴 것이다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT DATE(전부 자정, 2022-01-01 ~ 2024-12-31) · 고객마다 약 500건
  • 인덱스 IX_ORD_BIG_CUS_DT (CUS_ID, ORD_DT): 지난 토요일까지 이름은 T_ORD_BIG_X02 · BLEVEL 2 · 리프 약 3,000블록 · 통계 최신

원본 SQL ​

sql
SELECT /*+ INDEX_DESC(o T_ORD_BIG_X02) */
       o.ORD_DT AS prev_dt
  FROM T_ORD_BIG o
 WHERE o.CUS_ID = :cus
   AND o.ORD_DT < :cur_dt
   AND ROWNUM = 1

실행계획 학습용 예시 ​

xplan
[지난주 금요일 · 이름을 바꾸기 전]
-------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                   |      1 |        |      1 |00:00:00.01 |       3 |
|*  1 |  COUNT STOPKEY               |                   |      1 |        |      1 |00:00:00.01 |       3 |
|*  2 |   INDEX RANGE SCAN DESCENDING| T_ORD_BIG_X02     |      1 |      1 |      1 |00:00:00.01 |       3 |
-------------------------------------------------------------------------------------------------------
   1 - filter(ROWNUM=1)
   2 - access("O"."CUS_ID"=:CUS AND "O"."ORD_DT"<:CUR_DT)

[이번 주 월요일 · 같은 SQL]
-------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                   |      1 |        |      1 |00:00:00.01 |       3 |
|*  1 |  COUNT STOPKEY               |                   |      1 |        |      1 |00:00:00.01 |       3 |
|*  2 |   INDEX RANGE SCAN           | IX_ORD_BIG_CUS_DT |      1 |      1 |      1 |00:00:00.01 |       3 |
-------------------------------------------------------------------------------------------------------
   1 - filter(ROWNUM=1)
   2 - access("O"."CUS_ID"=:CUS AND "O"."ORD_DT"<:CUR_DT)

Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1 (U - Unused (1))
---------------------------------------------------------------------------
   2 -  SEL$1 / "O"@"SEL$1"
         U -  INDEX_DESC(o T_ORD_BIG_X02) / index specified in the hint doesn't exist

[화면 · CUS_000123 의 2024-12-30 주문]  직전 주문일 2022-01-04 → 재구매 간격 1,091일 (실제 직전 주문은 2024-12-27)

문제 ​

  1. SQL을 한 글자도 바꾸지 않았는데 결과가 바뀐 까닭을 두 실행계획과 Hint Report로 설명하시오.
  2. 인덱스의 이름이나 구성이 바뀌어도 결과가 바뀌지 않도록 SQL을 고치고, 고친 SQL이 몇 블록에서 멈추는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자