Skip to content
튜닝 연습파싱과 바인드 변수
PARSE-028

인프라팀의 세 가지 안: 「피킹을 끄고, 히스토그램을 지우고, 계획을 전부 잡아 두자」

실전DDL한빛유통573 / 700

상황 ​

지난달 정산 상태 탭이 날마다 다른 탭에서 느렸던 일(PARSE-002)에 이어, 오늘 아침에는 「등급별 매출」 화면이 C 등급에서 3만 블록을 읽었다. 인프라팀이 메일을 보냈다. "바인드 값 때문에 계획이 흔들리는 일을 한 번에 없애겠습니다. 피킹을 끄고, 히스토그램을 지우고, 계획 베이스라인을 자동으로 잡아 두면 계획이 바뀔 일이 없습니다. 금요일 밤 반영 예정입니다." 박팀장이 덧붙였다. "세 가지를 따로 평가해 주세요. 반대한다면 대신 무엇을 할지도요."

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_ST COMPLETE 90% · PENDING 8% · CANCEL 2% · FREQUENCY 히스토그램 · 6월 한 달 27,390건
  • M_CUS: 2,000행 · 30블록 · CUS_GD A 20명 · B 180명 · C 1,800명 · FREQUENCY 히스토그램
  • 인덱스 IX_ORD_BIG_DT · IX_ORD_BIG_DT_AMT (ORD_DT, ORD_AMT) · IX_ORD_BIG_DT_SEQ (ORD_DT, ORD_SEQ) · IX_ORD_BIG_CUS_DT (CUS_ID, ORD_DT) · PK_M_CUS
  • CURSOR_SHARING = EXACT · 바인드 피킹 켬 · SQL Plan Baseline 없음 · statistics_level = TYPICAL

원본 SQL ​

sql
-- 인프라팀 변경 요청 (금요일 22:00)
ALTER SYSTEM SET "_optim_peek_user_binds" = FALSE SCOPE = BOTH;                       -- ① 피킹 끄기
EXEC DBMS_STATS.SET_GLOBAL_PREFS('METHOD_OPT', 'FOR ALL COLUMNS SIZE 1');           -- ② 히스토그램 지우기 (그날 밤 다시 수집)
ALTER SYSTEM SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES = TRUE SCOPE = BOTH;          -- ③ 계획 자동 수집 · 고정

-- 영향을 받는 문장 셋
-- [S1] 등급별 매출 화면 (바인드 : 등급과 조회월)
SELECT c.CUS_GD, COUNT(*) AS ORD_CNT, SUM(o.ORD_AMT) AS AMT
  FROM M_CUS c, T_ORD_BIG o
 WHERE c.CUS_GD = :gd
   AND o.CUS_ID = c.CUS_ID
   AND o.ORD_DT >= TO_DATE(:p_ym || '01', 'YYYYMMDD')
   AND o.ORD_DT <  ADD_MONTHS(TO_DATE(:p_ym || '01', 'YYYYMMDD'), 1)
 GROUP BY c.CUS_GD;

-- [S2] 정산 상태 확인 · 취소 탭 (2019 강도현 · 상수 · 완료와 미결 탭도 같은 모양)
SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_AMT
  FROM (SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_AMT FROM T_ORD_BIG
         WHERE ORD_ST = 'CANCEL' ORDER BY ORD_DT DESC, ORD_SEQ DESC)
 WHERE ROWNUM <= 1000;

-- [S3] 월 매출 Q1 (바인드 : 조회월 · 커버링 인덱스)
SELECT COUNT(*), SUM(ORD_AMT)
  FROM T_ORD_BIG
 WHERE ORD_DT >= TO_DATE(:p_ym || '01', 'YYYYMMDD')
   AND ORD_DT <  ADD_MONTHS(TO_DATE(:p_ym || '01', 'YYYYMMDD'), 1);

실행계획 학습용 예시 · 상태 탭과 피킹 끄기 수치는 교재 11화 실측 ​

xplan
[S1 · 6월 · 지금 (피킹 켬 · 히스토그램 있음) · 등급마다 한 번의 Buffers]
                       A 등급    B 등급    C 등급
 A로 태어난 커서 (NL)      372     3,035    30,081    ← NESTED LOOPS + IX_ORD_BIG_CUS_DT
 C로 태어난 커서 (HASH)  5,858     5,858     5,858    ← T_ORD_BIG FULL + HASH JOIN
 등급마다 맞는 계획        372     3,035     5,858
 (A로 태어난 날은 A 372 → C 30,081 순서로 칸이 섞여 ACS가 한 번 뒤에 C를 HASH로 나눈다 · C로 태어난 날은 셋 다 1번 칸이라 그대로)

[S2 · 탭 셋 (상수)]  완료 1,016 · 미결 5,826 · 취소 5,826   (FREQUENCY 덕에 탭마다 맞는 계획)
[S3 · Q1]            어느 달이든 91                         (커버링 인덱스 범위 스캔)

[① 피킹 끄기를 내 세션에만 (ALTER SESSION SET "_optim_peek_user_binds" = FALSE)]
 S1 : 등급 값을 모른다 → CUS_GD E-Rows 667(1/3) → HASH 고정 · A 5,858 · B 5,858 · C 5,858
 S2 : 상수라 그대로 (1,016 · 5,826 · 5,826)
 S3 : 91 그대로
 (교재 11화) 상태 탭을 바인드로 쓴 문장 · 셋 다 인덱스 계획 · 취소 50,347 / OR가 든 바인드 페이징(rev02 모양) · 2페이지 1,005,991

[② 복사본 스키마에서 히스토그램을 지우고 다시 모은 뒤]
 S1 : CUS_GD E-Rows 667 → HASH 고정 · A 5,858
 S2 : 'CANCEL' E-Rows 333,333 → 인덱스 계획(INDEX FULL SCAN DESCENDING) · 취소 50,347 · 미결 13,510 · 완료 1,016
 S3 : 91 그대로

[③ 복사본에서 자동 수집을 켜고 하루 돌린 뒤 · DBA_SQL_PLAN_BASELINES]
 S1 : ACCEPTED 1개(그날 처음 수집된 NESTED LOOPS) · 그 뒤 HASH JOIN 계획은 ACCEPTED = NO로만 쌓인다 → C 30,081이 계속
 S2 : 탭마다 문장이 달라 베이스라인 셋 · 계획 그대로
 베이스라인 하루 1,940개 생성 · SYSAUX 사용 증가

문제 ​

  1. ①, ②, ③을 하나씩 위 측정으로 평가하시오. 각각 무엇을 고치고 무엇을 망가뜨리는지 문장별로 쓰시오.
  2. 서버 설정 대신 무엇을 고칠지 SQL로 제안하시오. 바인드 값 때문에 계획이 흔들리는 문장을 찾아내는 방법도 쓰시오.
  3. 인프라팀이 걱정하는 "계획이 흔들리는 일"을 제안보다 작은 범위로 막는 방법과 그 기준을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자