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

선두 컬럼이 세 종류뿐이라던 고객 상태 요약이 SKIP SCAN으로 인덱스를 4천 블록 넘게 읽는다

실전SELECT한빛유통114 / 700

상황 ​

고객센터 상담 화면에 「고객 주문 상태 요약」을 새로 붙였다. 고객 번호 하나로 상태별 주문 건수를 보여 주며, 상담원들이 하루 3,000번쯤 연다. 개발자는 고객으로 찾는 인덱스가 없다는 것을 알고 기존 인덱스에 INDEX_SS 힌트를 붙였다. 메모에는 이렇게 적혀 있다. "선두 ORD_ST는 3종뿐이라 SKIP SCAN이면 세 번만 찾아간다. 인덱스를 새로 만들 필요 없음." 그런데 한 번에 4,412블록을 읽는다. 박팀장은 대안을 비교해 오라고 했다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT 1,095일(하루 913건) · ORD_ST COMPLETE 90% · PENDING 8% · CANCEL 2% · CUS_ID 2,000명(고객당 500건)
  • 적재 규칙 때문에 PENDING과 CANCEL은 닷새에 하루(219일)에만 있다. 그래서 (ORD_ST, ORD_DT) 조합은 COMPLETE 1,095개, PENDING 219개, CANCEL 219개를 합쳐 1,533개다
  • 이 데이터에서는 고객 한 명의 주문이 모두 같은 상태다(CUS_000123은 500건 모두 COMPLETE)
  • 인덱스 IX_ORD_BIG_ST_DT_CUS (ORD_ST, ORD_DT, CUS_ID): ACC-001의 (ORD_ST, ORD_DT)에 CUS_ID를 덧붙인 인덱스 · BLEVEL 2 · 리프 약 4,350블록(리프 한 블록에 약 230항목) · 통계 최신 · 「취소 추이」(ORD_ST = 'CANCEL' AND ORD_DT 범위)와 「상태별 일 고객 목록」(ORD_ST = :st AND ORD_DT = :d)이 쓴다
  • 다른 인덱스는 IX_ORD_BIG_DT_AMT (ORD_DT, ORD_AMT)뿐이다 · 주문은 운영에서 계속 INSERT된다(교재 04화 실측: 인덱스 하나에 5만 건당 redo 약 11.8MB)

원본 SQL ​

sql
SELECT /*+ INDEX_SS(o IX_ORD_BIG_ST_DT_CUS) */
       o.ORD_ST, COUNT(*) AS ord_cnt
  FROM T_ORD_BIG o
 WHERE o.CUS_ID = :v_cus
 GROUP BY o.ORD_ST

실행계획 학습용 예시 · 건수와 조합 수는 적재 스크립트 그대로 · 적재 비용은 교재 04화 실측 ​

xplan
-------------------------------------------------------------------------------------------------------
| Id  | Operation            | Name                 | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                      |      1 |        |      1 |00:00:00.05 |    4412 |
|   1 |  SORT GROUP BY NOSORT|                      |      1 |      3 |      1 |00:00:00.05 |    4412 |
|*  2 |   INDEX SKIP SCAN    | IX_ORD_BIG_ST_DT_CUS |      1 |    500 |    500 |00:00:00.05 |    4412 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("O"."CUS_ID"=:V_CUS)
       filter("O"."CUS_ID"=:V_CUS)

[같은 SQL · 힌트를 떼면] TABLE ACCESS FULL 5,826

문제 ​

  1. 선두 컬럼이 3종인데도 SKIP SCAN이 4,412블록을 읽은 이유를 이 인덱스의 컬럼 구성과 데이터 분포로 설명하시오.
  2. 대안 넷을 비교하시오. ① 그대로 둔다(INDEX_SS) ② 힌트만 뗀다 ③ 고객이 선두인 인덱스를 새로 만든다 ④ 기존 인덱스의 순서를 (ORD_ST, CUS_ID, ORD_DT)로 바꾼다. 각각의 Buffers, 다른 화면에 주는 영향, 적재 비용을 쓰시오.
  3. 하나를 골라 SQL과 DDL을 작성하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자