Skip to content
튜닝 연습인덱스 스캔 효율과 테이블 액세스
ACC-014

PG사 불일치 주문번호 다섯 개를 찾는 데 정산 화면이 인덱스를 330블록 읽는다

중급SELECT한빛유통89 / 700

상황 ​

정산팀은 매일 아침 PG사가 보낸 「금액 불일치 주문」 목록을 받아 「주문번호 일괄 조회」 화면에 주문번호를 몇 개씩 붙여 넣는다. 보통 다섯 개 안팎이고 많으면 스무 개다. 화면은 기간 칸에 최근 석 달을 기본값으로 채워 함께 보낸다. 정산 담당 열 명이 하루 약 1,500번 조회한다. 개발자는 주문번호를 IN 목록으로 넘기니 INLIST ITERATOR가 번호마다 찾아갈 것이라고 했다. 그런데 주문 다섯 건을 찾는 데 335블록을 읽는다. 아래는 2024년 10 ~ 12월을 기간으로 다섯 건을 찾았을 때다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT 하루 913건(전부 자정) · 2024년 10 ~ 12월 83,996건(92일)
  • ORD_SEQ는 값이 겹치지 않는다. 하지만 PK도 유니크 제약도 없다(교재 데이터 그대로)
  • 인덱스 IX_ORD_BIG_DT_SEQ_AMT (ORD_DT, ORD_SEQ, ORD_AMT): 「정산 목록」 키 기반 페이징과 「기간 매출」이 쓴다(ACC-069) · BLEVEL 2 · 리프 약 3,890블록(리프 한 블록에 약 257항목) · CLUSTERING_FACTOR 약 1,000,000 · 통계 최신
  • 다른 인덱스는 없다 · 낮에는 주문이 하루 약 900건 INSERT된다

원본 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 ORD_SEQ IN (:n1, :n2, :n3, :n4, :n5)

실행계획 학습용 예시 · 건수는 적재 스크립트 그대로 · 인덱스 규모는 ACC-069와 같다 ​

xplan
------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                  | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                       |      1 |        |      5 |00:00:00.01 |     335 |
|*  1 |  FILTER                               |                       |      1 |        |      5 |00:00:00.01 |     335 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED | T_ORD_BIG             |      1 |      1 |      5 |00:00:00.01 |     335 |
|*  3 |    INDEX RANGE SCAN                   | IX_ORD_BIG_DT_SEQ_AMT |      1 |      1 |      5 |00:00:00.01 |     330 |
------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(TO_DATE(:V_TO,'YYYYMMDD')+1>TO_DATE(:V_FROM,'YYYYMMDD'))
   3 - access("ORD_DT">=TO_DATE(:V_FROM,'YYYYMMDD') AND "ORD_DT"<TO_DATE(:V_TO,'YYYYMMDD')+1)
       filter(("ORD_SEQ"=:N1 OR "ORD_SEQ"=:N2 OR "ORD_SEQ"=:N3 OR "ORD_SEQ"=:N4 OR "ORD_SEQ"=:N5))

문제 ​

  1. 주문 다섯 건인데 3번 줄이 330블록을 읽는 이유를 Predicate Information으로 설명하시오. 주문번호를 IN 목록으로 줬는데도 INLIST ITERATOR가 나오지 않은 이유도 설명하시오.
  2. (가) 기간을 날짜 목록으로 펼쳐 두 조건을 모두 IN 목록으로 주는 방법과 (나) 주문번호가 앞에 오는 인덱스를 만드는 방법을 읽는 블록 수로 비교하시오. 하나를 골라 SQL과 DDL을 작성하시오.
  3. 고른 방법의 대가를 쓰고, 담당자가 기간을 주문일 하루로 좁혀 조회하면 어느 쪽이 싼지 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자