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

화요일부터 읽은 블록 수 1위로 올라온 주문 요약 조회, 계획이 바뀌었으니 고정하자고 한다

기초SELECT한빛유통637 / 700

상황 ​

고객센터 화면과 모바일 앱 홈 화면은 같은 SQL로 고객 한 명의 상태별 주문 수와 금액(「주문 요약」)을 보여 준다. 화요일 오후 박팀장이 AWR 보고서를 보냈다. 「SQL ordered by Gets」 1위가 이 SQL이고, 월요일 보고서에서는 37위였다. 화요일 오전에 모바일 앱의 새 판이 나갔지만 DB 쪽 배포는 없었다. 오과장은 이렇게 말했다. "월요일 밤에 자동 통계 수집이 돌았으니 계획이 바뀐 거예요. 월요일 계획을 AWR에서 꺼내 베이스라인으로 박죠." 조민우가 AWR의 SQL 이력을 뽑았다.

테이블과 인덱스 ​

  • T_ORD: 100,000행 · 896블록 · 고객 2,000명 · 고객당 주문 약 50건
  • 인덱스 PK_T_ORD (ORD_SEQ) · IX_T_ORD_CUS_DT (CUS_ID, ORD_DT)
  • 통계: T_ORD의 LAST_ANALYZED는 지난주 목요일 22:07(월요일 밤에는 STALE이 아니어서 자동 수집이 건너뛰었다)
  • AWR: 1시간 간격 · 보존 8일 · Diagnostic Pack 계약 있음

원본 SQL ​

sql
-- 화면과 앱이 같이 쓰는 SQL (SQL_ID 8fz3m1wq2c7d4)
SELECT ORD_ST, COUNT(*) AS ORD_CNT, SUM(ORD_AMT) AS ORD_AMT
  FROM T_ORD
 WHERE CUS_ID = :cus_id
 GROUP BY ORD_ST;

-- 오과장 안 : 월요일 오전 스냅샷에서 계획을 꺼내 베이스라인으로 고정한다
DECLARE
  n PLS_INTEGER;
BEGIN
  n := DBMS_SPM.LOAD_PLANS_FROM_AWR(
         begin_snap   => 4417,
         end_snap     => 4419,
         basic_filter => q'[sql_id = '8fz3m1wq2c7d4']');
END;
/

실행계획 학습용 예시 ​

xplan
[DBA_HIST_SQLSTAT · SQL_ID 8fz3m1wq2c7d4 · 1시간 스냅샷]
 SNAP_ID  시작       PLAN_HASH_VALUE  EXECUTIONS_DELTA  BUFFER_GETS_DELTA  ROWS_PROCESSED_DELTA  ELAPSED_TIME_DELTA
    4418  월 10:00      1840227316             2,012            104,630                 4,628             1.21초
    4419  월 11:00      1840227316             2,105            109,460                 4,842             1.27초
    4442  화 10:00      1840227316           121,480          6,317,110               279,404            72.60초
    4443  화 11:00      1840227316           118,960          6,185,920               273,608            71.41초

[DBA_HIST_ACTIVE_SESS_HISTORY · 같은 SQL_ID · 화 10:00 ~ 12:00 · MODULE별 표본 수]
 MOBILE_HOME   13
 CS_ORDER       1

[DBA_OPTSTAT_OPERATIONS · 월요일 밤]
 22:00:03 ~ 22:14:41  gather_database_stats (auto optimizer stats collection) · 모은 테이블 3개 (T_ORD 없음)

[지금 커서 · ALLSTATS LAST · 고객 한 명]
Plan hash value: 1840227316

---------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                 |      1 |        |      2 |00:00:00.01 |      52 |
|   1 |  HASH GROUP BY                       |                 |      1 |      3 |      2 |00:00:00.01 |      52 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| T_ORD           |      1 |     50 |     50 |00:00:00.01 |      52 |
|*  3 |    INDEX RANGE SCAN                  | IX_T_ORD_CUS_DT |      1 |     50 |     50 |00:00:00.01 |       2 |
---------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("CUS_ID"=:CUS_ID)

문제 ​

  1. 오과장의 진단(통계 수집 때문에 계획이 바뀌었다)이 맞는지 위 자료로 판단하시오. 화요일에 이 SQL이 1위가 된 이유를 실행당 숫자로 설명하시오.
  2. 이 SQL의 일량 변화를 계획과 호출 횟수로 나눠 보는 진단 SQL을 쓰고, 오과장 안을 받아들일지와 실제로 고칠 곳을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자