Skip to content
튜닝 연습옵티마이저와 통계
OPT-035

상담원 80명이 띄워 두는 취소 주문 모니터가 첫 화면마다 주문 테이블을 통째로 읽는다

중급SELECT한빛유통625 / 700

상황 ​

상담팀의 「취소 주문 모니터」는 취소된 주문을 최신순으로, 고객 이름과 등급을 붙여 보여 준다. 상담원 80명이 띄워 두고 수시로 새로 고쳐 하루 약 1만 번 호출되는데, 거의 모두 첫 화면만 본다. 화면 프레임워크는 커서 하나를 열어 두고 스크롤할 때마다 20행씩 더 가져가는 방식(무한 스크롤)이라 SQL에 행 수 제한을 넣을 수 없다. 지난달 ORD_ST에 히스토그램을 걸었고(10화 정책서 1호), 이 화면을 위해 (ORD_ST, ORD_DT, ORD_SEQ) 인덱스도 만들었다. 그런데 계획은 그대로 FULL이다. 조민우: "인덱스가 있는데 왜 안 타죠? OPTIMIZER_INDEX_COST_ADJ를 낮춰 볼까요?"

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT DATE(전부 자정이라 같은 날짜의 주문이 많다) · ORD_ST CANCEL 20,000행(2%) · ORD_ST FREQUENCY 히스토그램
  • 인덱스 IX_ORD_BIG_ST_DT (ORD_ST, ORD_DT, ORD_SEQ): BLEVEL 2 · 리프 3,600블록 · 클러스터링 팩터 약 990,000(같은 상태 안에서 날짜순으로 줄 세우면 행마다 다른 블록이다)
  • M_CUS: 2,000행 · 30블록 · PK_M_CUS (CUS_ID)
  • 인스턴스 OPTIMIZER_MODE는 기본값 ALL_ROWS · 통계 최신

원본 SQL ​

sql
SELECT o.ORD_SEQ, o.ORD_DT, o.ORD_AMT, c.CUS_ID, c.CUS_NM, c.CUS_GD
  FROM T_ORD_BIG o, M_CUS c
 WHERE o.ORD_ST = 'CANCEL'
   AND c.CUS_ID = o.CUS_ID
 ORDER BY o.ORD_DT DESC, o.ORD_SEQ DESC

실행계획 학습용 예시 · 교재 04화 규모 ​

xplan
[첫 화면 20행을 받고 커서를 닫았을 때]
------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |           |      1 |        |     20 |00:00:00.09 |    5856 |          |
|   1 |  SORT ORDER BY      |           |      1 |  20000 |     20 |00:00:00.09 |    5856 | 1213K (0)|
|*  2 |   HASH JOIN         |           |      1 |  20000 |  20000 |00:00:00.08 |    5856 | 1557K (0)|
|   3 |    TABLE ACCESS FULL| M_CUS     |      1 |   2000 |   2000 |00:00:00.01 |      30 |          |
|*  4 |    TABLE ACCESS FULL| T_ORD_BIG |      1 |  20000 |  20000 |00:00:00.07 |    5826 |          |
------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("C"."CUS_ID"="O"."CUS_ID")
   4 - filter("O"."ORD_ST"='CANCEL')

[같은 SQL + /*+ INDEX(o IX_ORD_BIG_ST_DT) */ 로 끝까지 받았을 때 — 비교용]  Buffers 약 60,000 (T_ORD_BIG 쪽 20,063)

문제 ​

  1. 히스토그램으로 E-Rows가 정확한데도 옵티마이저가 인덱스를 두고 FULL을 고른 이유를 쓰시오. 끝까지 받는다면 그 판단이 맞는지도 손익분기점으로 판단하시오.
  2. 프레임워크는 그대로 두고 첫 화면이 빨리 뜨도록 SQL을 고치시오. 그 방법이 통하는 조건과, 조민우의 안을 포함한 다른 방법의 대가를 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자