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

리포팅 도구로 내려받는 고객별 주문 원장이 인덱스 순서대로 100만 번 테이블을 찾아간다

중급DDL한빛유통118 / 700

상황 ​

마케팅팀은 매달 초 리포팅 도구로 「고객별 주문 원장」을 CSV로 내려받는다. 고객 번호, 주문일 순으로 100만 행 전부다. 다운로드는 바로 시작되는데 끝나기까지 오래 걸리고, 그동안 서버 CPU 하나가 계속 바쁘다. 리포팅 도구는 접속할 때마다 세션을 OPTIMIZER_MODE = FIRST_ROWS_10으로 바꾼다. 공급사는 이렇게 설명한다. "첫 화면을 빨리 띄우기 위한 기본값이다." 같은 SQL을 SQL*Plus(ALL_ROWS)에서 돌리면 계획이 다르다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록(블록당 약 172행) · ORD_SEQ 순으로 쌓였다 · CUS_ID NOT NULL 2,000명 · 한 고객의 주문은 ORD_SEQ 2,000건 간격이라 테이블 전체에 흩어져 있다
  • 인덱스 IX_ORD_BIG_CUS_DT (CUS_ID, ORD_DT): 「고객 주문 이력」(CUS_ID = :c) 화면용 · BLEVEL 2 · 리프 약 3,600블록 · CLUSTERING_FACTOR 약 1,000,000 · 통계 최신 · 다른 인덱스는 이 SQL과 상관없다
  • 세션의 정렬 작업 영역은 약 20MB까지다(PGA 자동 관리)
  • 주문은 운영에서 계속 INSERT되고, 금액 정정 UPDATE가 하루 수십 건 있다(교재 04화 실측: 인덱스 하나에 5만 건당 redo 약 11.8MB)

원본 SQL ​

sql
-- 리포팅 도구 세션: ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS_10;
SELECT CUS_ID, ORD_DT, ORD_AMT
  FROM T_ORD_BIG
 ORDER BY CUS_ID, ORD_DT

실행계획 학습용 예시 · 인덱스 규모는 교재 08화의 (CUS_ID, ORD_AMT) 리프 3,624블록에서 어림 ​

xplan
[리포팅 도구 — FIRST_ROWS_10]
----------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                   |      1 |        |   1000K|00:00:04.62 |    1003K|
|   1 |  TABLE ACCESS BY INDEX ROWID| T_ORD_BIG         |      1 |   1000K|   1000K|00:00:04.62 |    1003K|
|   2 |   INDEX FULL SCAN           | IX_ORD_BIG_CUS_DT |      1 |   1000K|   1000K|00:00:00.41 |    3603 |
----------------------------------------------------------------------------------------------------------
(0번 줄 Buffers 정확한 값 1,003,603 · 버퍼 캐시에 테이블이 다 올라와 있을 때)

[SQL*Plus — ALL_ROWS]
-------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads | Writes | Used-Mem | Used-Tmp |
-------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |      1 |        |   1000K|00:00:01.71 |    5826 |  4102 |   4102 |          |          |
|   1 |  SORT ORDER BY     |           |      1 |   1000K|   1000K|00:00:01.71 |    5826 |  4102 |   4102 | 2142K (1)|    33M   |
|   2 |   TABLE ACCESS FULL| T_ORD_BIG |      1 |   1000K|   1000K|00:00:00.09 |    5826 |     0 |      0 |          |          |
-------------------------------------------------------------------------------------------------------------------------------

문제 ​

  1. 같은 SQL이 리포팅 도구에서는 1,003K블록, SQL*Plus에서는 5,826블록과 TEMP 33MB를 쓰는 이유를 두 실행계획의 스캔 방식과 OPTIMIZER_MODE로 설명하시오.
  2. 세션 설정을 건드리지 않고 이 원장이 정렬 없이, 테이블에도 가지 않고 나오도록 인덱스를 설계하시오. 기존 인덱스를 어떻게 할지와 그 대가도 쓰시오.
  3. INDEX FAST FULL SCAN으로는 왜 이 일을 할 수 없는지 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자