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

새 커버링 인덱스를 다른 화면은 다 쓰는데 월 영업 매장 수 위젯만 옛 계획 그대로다

중급SELECT버거629 / 700

상황 ​

본사 대시보드의 「월 영업 매장 수」 위젯은 하루 2,000번쯤 호출된다. 지난주 다른 화면을 위해 ORD_X04 (ORD_DT, SHOP_NO)를 만들자 같은 조건의 조회 화면들은 모두 그 인덱스로 바뀌었는데, 이 위젯만 그대로다. 계획의 Note에 낯선 줄이 하나 있다. 작업 기록을 뒤지자 작년 1월 오과장의 메모가 나왔다. "해가 바뀌는 기간(12/16 ~ 1/15)을 고르면 E-Rows가 수십 배로 뛰어 FULL(22,422블록)로 바뀜. 문자 날짜 탓. ORD_X01 계획의 Outline으로 프로파일을 만들어 고정함."

테이블과 인덱스 ​

  • ORD: 1,000,000행 · 22,422블록 · ORD_DT VARCHAR2(8) · 한 달 약 41,700건 · 매장 200곳 · 이 테이블을 FULL로 읽는 비용은 약 6,083
  • ORD_X01 (ORD_DT, ORD_HMS): 리프 3,774 · 클러스터링 팩터 22,223(날짜순 적재 · 작년부터 있다)
  • ORD_X04 (ORD_DT, SHOP_NO): 지난주 생성 · BLEVEL 2 · 리프 3,050블록
  • SQL 프로파일 PROF_WIDGET_SHOPS: 작년 1월 DBMS_SQLTUNE.IMPORT_SQL_PROFILE로 만들었다 · CATEGORY DEFAULT · FORCE_MATCHING YES · Tuning Pack 계약 있음

원본 SQL ​

sql
SELECT COUNT(DISTINCT SHOP_NO) AS shop_cnt
  FROM ORD
 WHERE ORD_DT BETWEEN :v_from AND :v_to

실행계획 학습용 예시 · 교재 04화의 문자 날짜 E-Rows ​

xplan
[지금 — 2013년 11월]
-------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |          |      1 |        |      1 |00:00:00.04 |    1071 |
|   1 |  SORT AGGREGATE                       |          |      1 |      1 |      1 |00:00:00.04 |    1071 |
|   2 |   VIEW                                | VW_DAG_0 |      1 |    200 |    200 |00:00:00.04 |    1071 |
|   3 |    HASH GROUP BY                      |          |      1 |    200 |    200 |00:00:00.04 |    1071 |
|*  4 |     FILTER                            |          |      1 |        |  41712 |00:00:00.03 |    1071 |
|   5 |      TABLE ACCESS BY INDEX ROWID BATCHED| ORD    |      1 |   4065 |  41712 |00:00:00.03 |    1071 |
|*  6 |       INDEX RANGE SCAN                | ORD_X01  |      1 |   4065 |  41712 |00:00:00.01 |     139 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   4 - filter(:V_FROM<=:V_TO)
   6 - access("ORD_DT">=:V_FROM AND "ORD_DT"<=:V_TO)

Note
-----
   - SQL profile PROF_WIDGET_SHOPS used for this statement

[프로파일 안의 힌트 — DBA_SQL_PROFILES 의 SIGNATURE 로 꺼냄]
   BEGIN_OUTLINE_DATA
   IGNORE_OPTIM_EMBEDDED_HINTS
   ALL_ROWS
   OUTLINE_LEAF(@"SEL$5771D262")
   INDEX_RS_ASC(@"SEL$5771D262" "ORD"@"SEL$1" ("ORD"."ORD_DT" "ORD"."ORD_HMS"))
   BATCH_TABLE_ACCESS_BY_ROWID(@"SEL$5771D262" "ORD"@"SEL$1")
   USE_HASH_AGGREGATION(@"SEL$5771D262")
   END_OUTLINE_DATA

[같은 조건을 쓰는 「월 매장별 주문 수」 화면 — 지난주부터]  INDEX RANGE SCAN ORD_X04 · Buffers 129

문제 ​

  1. 새 인덱스가 있는데도 이 위젯만 옛 계획으로 도는 이유를 Note와 프로파일 안의 힌트로 설명하시오. 이런 프로파일이 SQL plan baseline과 다른 점도 쓰시오.
  2. 운영 화면에 영향을 주지 않고 프로파일 없는 계획을 먼저 확인한 뒤 바로잡으시오. 작년에 프로파일을 만든 이유가 지금도 남아 있는지 판단하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자