테마
16화 · 처음으로 시스템 전체를 본다
🗓️ 6월 24일 (월) · 지난주는 숨을 고른 주였다 · 무대
ora-hanorder(한빛유통) · 4막의 첫 화오늘 배울 것: AWR 리포트는 두 번 검침한 값의 차이이고, 칸 하나는 결론이 아니다. 운영팀의 "히트율 99점대니 I/O는 괜찮다 · CPU 100%니 늘리자"와 개발팀의 "1위만 고치면 된다"를 9칸으로 다시 읽는다. 오늘은 조각을 고치지 않는다(리비전 없음). 대신 15화의 부하 발생기로 붐비는 오전을 만들고, 양식 세 가지(T5 시스템 성능 리포트 · T7 워크로드 프로파일 · T8 정기 점검)를 제정한다.
파일 세 개
| 파일 | 무엇을 하나 | 시간 | |
|---|---|---|---|
| 읽는다 | 1_사건.md | 이름 없는 민원에서 시작한다. 누적이 아니라 뺄셈을 배우고, 방재실의 검침 대장을 보고, 리포트 한 장을 9칸 순서로 읽으며 세 문장을 하나씩 뒤집는다. 지난주에 고친 배치가 시스템에 남긴 자국을 재고, 선배가 만든 '한 시간'을 처음 리포트로 읽는 하루 | 40분 |
| 한다 | 3_실습과_기록.md | SOP 9단계 · 구간 A · B(12분씩) · 리포트 · 9칸 직접 읽기 · 비교 리포트 · SQL 리포트 · PDB 레벨 · (선택) 한 시간 · T5 · T7 · T8 1호 | 90~120분(+62분 선택) |
| 찾는다 | 2_파고들기.md | 스냅샷과 델타 · 루트와 PDB · SOP · 9칸 각각 · Instance Efficiency의 식 · Host CPU · Time Model의 맞지 않는 줄 · SQL 목록이 뽑히는 기준 · 비교 리포트 · DBA_HIST_* 지도 · 부하 모델의 Q2 | 필요할 때 |
1을 읽고 3을 따라 한다. 2는 막힐 때 펼친다. 시간이 없는 주에는 1_사건을 중단 지점 1까지 읽고 3_실습은 STEP 0, 1, 3, 4, 6, 10만 한다(약 70분, 부하 24분 포함).
지난 화에서 들고 오는 것
| 15화 | PKG_LOAD_DRIVER: 6조각 현재판을 섞어 돌리는 부하 발생기(환경 폴더 L1) · "16화: STEADY 부하 위에서 AWR" · 보정 배치 ADJ_rev00 → rev01 · T3 2호 12번 ① rev01 운영 소요를 다시 잰다(6/17) |
| 07화 | 히트율은 건강 지표가 아니다 · "AWR의 Instance Efficiency에 줄지어 나오는 히트율들 → 16화" · resmgr:cpu quantum(CPU 2개 · 동시 4세션) |
| 08화 | Q2 「먼저 묶고 붙이기」 보류안: "16화에서 이 SQL이 CPU 상위에 오르면 rev02로 재검토" · Group-by Placement(VW_GBC_) |
| 04 · 14화 | T2-002 IX_ORD_BIG_DT 폐기(선결 조건 DBA_INDEX_USAGE 관찰) · P1 rev02의 TRUNCATE + APPEND |
| 01화 | V$는 누적, AWR은 두 스냅샷의 델타 |
그리고 월요일 아침, 메시지가 세 통 와 있다.
"보정 rev01, 6/17 첫 운영 10시 정각 시작 10시 7분 끝. 오늘도 10시 6분." (오과장, 08:52) "오전 내내 시스템 전체가 느리다는 민원. 히트율은 늘 99점대 초록불이라 I/O는 문제없음. CPU 100% → 증설 검토. 개발팀은 Top SQL 1위만 고치면 된다고. 왜 전체가 느린 겁니까?" (박팀장, 09:10) "지난 월요일(6/17) 10시 반쯤 정산 등록 화면이 몇 분 동안 안 넘어갔어요." (조민우, 09:14)
오늘의 전개 — 세 번 틀린다, 세 번 다 칸 하나로
| 내가 믿은 것 | 측정(연습 DB · 구간 A 9분 · 3세션 · 생각 시간 0) | |
|---|---|---|
| 09:30 | "V$SQL을 경과 시간 순으로 세우면 된다" | 누적으로는 '오전'을 볼 수 없다 → 두 번 찍어서 뺀다(AWR) |
| 10:35 | (① 머리) | Elapsed 9.00분 · DB Time 28.08분 → 평균 활성 세션 3.12(CPU 2) |
| 10:55 | "Buffer Hit 99.99%니 I/O는 문제없다" | 같은 구간 DB Time의 11.1%가 쓰기 I/O 대기다(enq: RO 6.6 · local write wait 3.2 · direct path sync 1.3). 히트율은 쓰기를 세지 않는다 |
| 11:30 | "CPU 100%니 늘리자" | 맞는 말이다. DB CPU 2.01초/초 = cpu_count 2. 그런데 늘려서 줄어드는 것은 CPU를 기다린 25.1%뿐이다 · 호스트는 32 CPU · %Idle 92.5 |
| 11:45 | "시퀀스가 범인(Time Model 92.6%)" | 그 시퀀스를 쓰는 SQL의 Elapsed는 6.6초. 맞지 않는 칸은 결론에 쓰지 않는다 |
| 13:00 | "1위가 범인" | Elapsed · CPU · Gets 1위는 Q2(실행당 5,834블록 = 바닥 · 16,525번) · Executions 1위는 보정 배치 INSERT 99,870 · 실행 0인 PL/SQL 셋이 32%씩 · Captured 67.2% |
| 13:40 | (08화 조건) | Q2 = DB CPU의 47.5%로 조건 충족. 그런데 실행계획에 VW_GBC_5가 있다. 부하 모델의 Q2는 운영 문장이 아니었다. 스칼라 한 줄이 빠져 CPU 10번 29~30cs(운영 rev01 113~116 · 08화 보류안 29~32) |
| 14:20 | (⑨ 대조) | 5조각은 부하 기록과 맞다 · P1은 3,354 vs 2,131: TRUNCATE의 커서 무효화 |
| 14:50 | "보정 배치를 고쳤으니 전체가 빨라진다" | 배치는 232 → 38cs(6배). 구간 DB time 28.1 → 28.2분(%Diff 0.4) · Executes −26.6% · Execute to Parse % 73.05 → 63.28(고쳤더니 '효율'이 떨어졌다) |
| 15:40 | (PDB) | PDB 리포트에는 Instance Efficiency · Host CPU · Instance CPU가 없다 · awr_pdb_autoflush_enabled는 이 버전 기본값이 TRUE · 루트 수동 스냅샷은 PDB에 생기지 않는다 → 루트에서 본다 |
| 16:00 | (한 시간) | 선배가 정한 '한 시간'(선택 실습): DB Time 181.09분 · CPU 대기 23.8% · enq: TX 5.5%(853번 · 평균 702ms) · 그 SQL은 목록에 없다 → 결론 '문제는 CPU를 먹는 일의 양, 락은 부차' · 조민우 씨의 10시 반은 리포트에 없다(→ 17화) |
왜 이렇게 짰을까? 15화까지는 늘 SQL이 먼저 있었다. 오늘은 민원에 SQL이 없다. 시스템 전체를 보는 첫날에 배울 것은 리포트의 칸 이름이 아니라 칸끼리 맞춰 보는 습관이다. 세 문장 모두 사실인 칸에서 나왔고, 셋 다 다른 칸이 반박했다. 그리고 이 화는 평균을 끝까지 의심하지 않는다. 한 시간의 결론은 17화에서 다시 연다.
오늘 배우는 한 문장
AWR 리포트는 두 번 검침한 값의 차이이고, 칸 하나는 결론이 아니다. 히트율이든 CPU든 1위든, 한 칸에서 읽은 것을 다른 칸이 같은 말로 뒷받침할 때까지 맞춰 본다. 그리고 리포트의 모든 숫자는 그 구간의 평균이다.
| 구간 A(9분 · 보정 rev00) | 그 칸 | 다른 칸에서 본 것 |
|---|---|---|
| 히트율 | Buffer Hit 99.99% | 쓰기 I/O 대기 11.1% · physical writes 3,475/초 |
| CPU | DB CPU 2.01/초(= cpu_count) | 늘리면 줄어드는 것 25.1% · 일 자체 64.5% |
| 1위 | Q2 rev01 Elapsed 663.6초 | 실행당 5,834블록(바닥) × 16,525번 · Executions 1위는 다른 문장 |
| Time Model | sequence load 92.6% | 그 시퀀스를 쓰는 SQL 6.6초 |
| 보정 배치 개선(A → B) | 배치 6배 | 시스템 DB Time 0.4% |
🔑 오늘의 비유 — 지하 2층 방재실의 검침 대장
| 방재실 | 오라클 |
|---|---|
| 층별 계량기: 건물이 생긴 날부터 숫자가 올라가기만 한다 | V$ 누적 통계(← 01화 V$MYSTAT) |
| 매시 정각에 계량기를 읽어 대장에 한 줄씩 적는다 | AWR 자동 스냅샷(1시간) |
| "지금 하나 더 읽어 둬" | 수동 스냅샷 CREATE_SNAPSHOT |
| 두 줄을 빼면 그 시간의 사용량이 나온다 | AWR 리포트 = 델타 |
| 역률 99.6% 초록불: 얼마나 쓰는지는 알 수 없다 | Instance Efficiency(히트율들) |
| 계약 전력: 건물이 한 번에 받을 수 있는 상한 | cpu_count 2(Free) |
| 수요 제어기가 에어컨을 번갈아 끈다. 고장이 아니라 차례를 기다리는 것이다 | resmgr:cpu quantum |
| 층별 사용량 순위 | SQL ordered by · Segments by Logical Reads |
| 그 한 시간 안의 5분 정전은 대장에 한 줄로 묻힌다 | 평균: 구간 안의 '언제'는 리포트에 없다(→ 17화) |
앞에서 나온 비유도 다시 쓴다. 07화 탕비실 픽업 선반(히트율 = 지하 카페에 내려가지 않은 비율), 15화 지하 1층 수발실(오늘 내려간 방재실보다 한 층 위다. 행마다 오가는 행낭 = 보정 배치 rev00의 30만 번), 14화 하역장(P1의 APPEND. 오늘은 그 하역이 쓰기 I/O로 보였다)이다.
☠️ 오늘의 함정 — 사실인 칸에서 나온 틀린 결론
Buffer Hit 99.99 % → 사실. 그런데 히트율은 쓰기를 안 센다 (쓰기 I/O 대기 11.1 %)
DB CPU 2.01 / 초 = cpu_count → 사실. 그런데 CPU 를 늘려 줄어드는 건 기다림 25.1 % 뿐
Elapsed 1위 Q2 → 사실. 그런데 실행당 5,834 블록 = 바닥 · 1위인 이유는 횟수
Executions 목록에 없는 문장 → 안 돈 게 아니다. 목록은 실행 수로 뽑지 않는다 (Captured 67.2 %)
Time Model sequence load 92.6 % → 같은 리포트의 SQL 은 6.6 초 — 맞지 않는 칸
보정 배치 6배 → 시스템 DB Time 0.4 % · 그리고 Execute to Parse % 는 10 포인트 떨어졌다
부하 발생기의 Q2 → 운영 Q2 rev01 이 아니었다 (스칼라 한 줄) — 리포트는 '우리가 만든 부하의 사진'실습 준비
bash
docker start ora-hanorder15화를 마친 상태에서 시작한다. 전제는 실습/00_준비와_점검.sql이 확인한다(T_ORD_BIG 100만 · 인덱스 3 · ORD_ST 히스토그램 · T_ORD_STLM 10만 · T_STLM_NUM 0 · PKG_ORD_STLM VALID · PKG_LOAD_DRIVER VALID · 도는 드라이버 세션 0). 부하 발생기는 다시 설치하지 않는다.
PowerShell에서는 먼저
$OutputEncoding = New-Object System.Text.UTF8Encoding $false한 줄을 실행한다. SYS 스크립트(_SYSDBA)는 Git Bash에서MSYS_NO_PATHCONV=1 docker exec -i ora-hanorder sqlplus -s / as sysdba < …로 돌린다. 접두사를 빼면/가 경로로 바뀐다.
| 스크립트 | 무엇 | 계정 | 소요 |
|---|---|---|---|
실습/00_준비와_점검.sql | 전제 · 원본 지문 · 보정 배치 복사본(C16) | sqlp | 10초 |
실습/01_AWR_현황_SYSDBA.sql | SOP 1 · 2 · 3: 어디서 · 팩 · 간격 · 보존 · 자원 | SYS | 수 초 |
★ 실습/02_구간_스냅샷_SYSDBA.sql + 발사기 | SOP 4~7: 창 둘 · 구간 A · B(보정 배치 +4분) · (선택) H | SYS + sqlp | 12분 × 2(+62분) |
★ 실습/03_AWR_리포트_SYSDBA.sql | 리포트 한 장 → awr_A.txt | SYS | 수 초 |
★ 실습/04_9칸_직접_읽기_SYSDBA.sql | 9칸을 DBA_HIST_*에서 · A · B · H 나란히 · 대조 | SYS | 수 초 |
★ 실습/05_AWR_비교_SYSDBA.sql | 두 구간 비교 → awr_diff_AB.txt | SYS | 수 초 |
실습/06_AWR_SQL_리포트_SYSDBA.sql | SQL 하나의 리포트 | SYS | 수 초 |
실습/07_PDB_레벨_AWR_SYSDBA.sql | PDB 레벨 AWR은 어디까지 | SYS + sqlp | 10초 |
실습/08_정기점검_SYSDBA.sql | T8 1호의 숫자 | SYS | 수 초 |
실습/09_부하모델의_Q2.sql | 부하 모델의 Q2 vs 운영 Q2(부하 없이) | sqlp | 15초 |
실습/99_정리.sql | C16 삭제 · 15화 종료 상태 확인 | sqlp | 수 초 |
두 번 돌려도 판정은 같다. 구간 A와 B를 두 번씩 돌렸다. 순위, 비율의 방향, 실행 수는 같고 초와 퍼센트만 조금 흔들린다(범위는
2_파고들기 §15). 원본 테이블에는 한 줄도 쓰지 않는다. 발사기가 런 앞뒤로 원본 지문을 찍는다. AWR 스냅샷은 지우지 않는다. 17화에서 다시 연다. ℹ️ 실습은 모두 Docker로 띄운 Oracle Database Free 한 대에서 끝난다. AWR, 비교 리포트, SQL 리포트, PDB 리포트가 모두 Free에 있다(진단 팩 포함, EE에서는 별도 구매). Free는 CPU가 2개라 'CPU를 늘린 뒤'는 잴 수 없다. 그래서 늘렸을 때 줄어드는 최대치(CPU 대기의 몫)로 대신한다. 대규모 EE 환경은 별권에서 다룬다.
이 화의 산출물
| 무엇 | 어디 |
|---|---|
| AWR SOP 9단계 · 읽는 순서 9칸 | 2_파고들기 §3 |
| T5 시스템 성능 리포트: 제정 · 1호(T5-001) | T5 양식 · 3_실습 STEP 10 |
| T7 워크로드 프로파일: 제정 · 1호(WP-16A · B · H) | T7 양식 · STEP 10 |
| T8 정기 점검: 제정 · 1호(6/24) | T8 양식 · STEP 10 |
리비전/ | 없다. 이 화는 SQL을 고치지 않는다(08화 정합성 체크리스트는 해당 없음, 이유는 T5-001 9번) |
이 화가 다음으로 넘기는 것
| 무엇 | 어디로 |
|---|---|
| 구간 H: 한 시간 리포트 한 장으로 낸 결론 · 같은 인자로 같은 런을 다시 만들어 시간 축으로 편다 · 조민우 씨의 "6/17 10시 반 몇 분" | 17화 |
| ADDM 요약 1위 Sequence Usage 92.64: 근거 줄(Time Model)이 SQL의 경과 시간과 맞지 않는다 · 권고 "larger cache size"를 무엇으로 검증하나 | 17화 |
| MODULE · ACTION으로 SQL을 조각에 묶기: ASH에도 같은 칸이 있다 | 17화 |
| Q2 보류안: 08화 재검토 조건 충족(모델의 가벼운 Q2로도 CPU 1위) · T1 절차 | 18화 |
T2-002 IX_ORD_BIG_DT 폐기: 선결 조건 중 인덱스 사용 관찰(T8 ⑥)을 시작했다 · 운영 SQL 전수 조사는 남았다 | 18화 |
| T5 · T7 · T8의 규칙: 칸 하나로 결론을 내지 않는다 · 비율 옆에 분자 · 분모 · 프로파일 ID 없는 리포트는 무효 → 사내 튜닝 표준(T6) 후보 | 18화 |
← 15b화 「같은 답을 두 번 계산하지 마라」 · 교재 전체 안내 · 다음 → 17화 「평균은 거짓말을 한다」