테마
L1 · ora-hanorder — ㈜한빛유통 통합주문 HANORDER ★ 본편 무대
포트 1521 · 계정
sqlp/sqlp· 크기 약 95MB · 쓰는 화 01~13, 15 (16화와 17화도 15화가 만든 부하 발생기로 여기서 시작한다) 이 컨테이너 하나만 있으면 01~13화를 진행할 수 있다. 만드는 절차는../../01_첫_고객사_ora-hanorder.md에 있다.
이 폴더의 파일 — 번호 순서대로 한 번씩
| # | 파일 | 누가 실행 | 무엇 | 실측 |
|---|---|---|---|---|
| 00 | 00_측정권한_부여.sql | SYS | sqlp가 실행계획을 볼 수 있게 권한을 준다. 빠뜨리면 ORA-01031이 난다 | 1초 |
| 01 | 01_구시스템_스키마A.sql | sqlp | 구 주문시스템(2015~)의 테이블 6개: DEPT EMP SALGRADE PRODUCTS CUSTOMERS ORDERS | 5.5초 |
| 02 | 02_신시스템_스키마B.sql | sqlp | 신 주문시스템(2019~, 강도현)의 테이블 8개: M_* 4개 + T_* 4개, T_ORD_BIG 100만 건 | 16.5초 |
| 03 | 03_환경검증.sql | sqlp | 테이블 14개의 행수 · 공간 · 무인덱스 · 첫 실행계획 한 장 판정 | 3초 |
| 04 | 04_상태복구.sql | sqlp | 하루가 지나 E-Rows가 틀어졌을 때 01화의 전제 상태로 되돌린다(필요할 때만) | 3초 |
| 05 | 05_PKG_LOAD_DRIVER.sql · 05_부하_돌리기.sh · 05_부하_돌리기.ps1 | sqlp | 부하 발생기(15화에서 만들고 16화와 17화가 쓴다). 설치는 1번만 하고, 그다음부터는 발사기로 돌린다. 자세한 내용은 §부하 발생기 | 설치 수 초 |
bash
# Git Bash — 이 폴더에서
MSYS_NO_PATHCONV=1 docker exec -i ora-hanorder sqlplus -s / as sysdba < 00_측정권한_부여.sql
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 01_구시스템_스키마A.sql
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 02_신시스템_스키마B.sql
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 03_환경검증.sqlpowershell
# PowerShell — 이 폴더에서 (-Encoding UTF8 을 빼면 한글 주석이 깨진다)
Get-Content 00_측정권한_부여.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s / as sysdba
Get-Content 01_구시스템_스키마A.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1
Get-Content 02_신시스템_스키마B.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1
Get-Content 03_환경검증.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1안에 무엇이 있나 — 한 계정에 두 시스템
01화에서는 user_tables를 조회하다가 이름 규칙이 두 종류라는 걸 알게 된다. 두 종류는 각각 아래 두 스크립트가 만든다.
구 시스템 (스키마 A) — 접두어 없는 영어 이름 · 2015년
| 테이블 | 행수 | 성격 |
|---|---|---|
DEPT / EMP / SALGRADE | 4 / 14 / 5 | 오라클 고전 예제 SCOTT. 개념 확인, 소량 조인용 |
PRODUCTS | 2,000 | 상품 |
CUSTOMERS | 20,000 | 고객. grade A 1% / B 9% / C 90% |
ORDERS | 200,000 | 주문. status COMPLETE 90% / PENDING 8% / CANCEL 2%. 인덱스 3개(PK_ORDERS · ORDERS_X_CUST · ORDERS_X_DATE) |
지금은 쓰지 않지만 지우지 못한 시스템이라는 설정이다. 01화 §6에서 "5배 작은데 인덱스는 3개"인 대조군으로 쓴다.
신 시스템 (스키마 B) — M_ / T_ 접두어 · 2019년 강도현
| 테이블 | 행수 | 성격 |
|---|---|---|
M_RGN | 8 | 지역 코드 |
M_ITM | 100 | 상품 |
M_ITM_PRC_HIS | 100 | 가격 이력. (ITM_ID, TO_YMD)로 최신 1건을 찾는 조회의 소재 |
M_CUS | 2,000 | 고객. CUS_GD A 1% / B 9% / C 90%. CUS_ID가 VARCHAR2('CUS_000123') |
T_ORD | 100,000 | 주문 |
T_ORD_DET | 200,000 | 주문상세(주문당 1~3건) |
T_ITM_EVL | 5,000 | 상품평가. M:1:M 조인 폭증(08화) 재현용 |
T_ORD_BIG | 1,000,000 | PK도 인덱스도 없다. ORD_ST 90/8/2 · ORD_DT 3년치. 19화의 주인공 |
핵심은 편향이다. 값이 고르게 퍼져 있으면 히스토그램(10화)도, 손익분기점(04화)도, 바인드 피킹(11화)도 배울 수 없다. 그래서 이 데이터는 일부러 치우쳐 있고, 일부러 인덱스가 없다.
⚠️ M_CUS.CUS_ID는 문자열이고 CUSTOMERS.cust_id는 숫자다. 두 시스템을 한 쿼리에서 섞으면 안 된다. 둘이 같은 컨테이너에 있는 건 "같은 회사의 구 시스템과 신 시스템"이라는 설정 때문이다.
ERD: 구시스템_스키마A_ERD.md · 신시스템_스키마B_ERD.md (신 시스템은 FK가 0개라서 ERD의 관계선은 사람이 컬럼명을 보고 그린 것이다. 01화 §4와 §5에서 직접 확인한다.)
검증 기대값 (03_환경검증.sql)
생성 스크립트는 난수 시드를 고정한다(
DBMS_RANDOM.SEED). 그래서 행수와 블록 수뿐 아니라 금액까지 누가 언제 설치해도 같다.[1b]에서T_ORD_BIG금액 합계가 255,398,623,700으로 나오면 내 데이터는 교재와 한 바이트도 다르지 않다.
DEPT | 4 | M_RGN | 8 |
EMP | 14 | M_ITM | 100 |
SALGRADE | 5 | M_ITM_PRC_HIS | 100 |
PRODUCTS | 2,000 | M_CUS | 2,000 |
CUSTOMERS | 20,000 | T_ORD | 100,000 |
ORDERS | 200,000 | T_ORD_DET | 200,000 |
T_ORD_BIG | 1,000,000 | ||
used_mb | ≈ 95 | ||
T_ORD_BIG 인덱스 수 | 0 |
마지막으로 실행계획이 한 장 나온다.
xplan
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.03 | 5827 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.03 | 5827 |
|* 2 | TABLE ACCESS FULL | T_ORD_BIG | 1 | 333K| 20000 |00:00:00.03 | 5827 |
E-Rows 333K대A-Rows 20,000, 16배 오추정이다. 옵티마이저는ORD_ST의 값 3개가 고르게 퍼져 있다고 보고 100만/3으로 추정했지만, 실제CANCEL은 2%다. 환경 구축을 마치는 순간 첫 사건이 이미 눈앞에 와 있다. 이 숫자는 01화에서 다시 본다.
⏰ 하루 지나면
E-Rows가 333K가 아니라 20000으로 나올 수 있다 — 고장이 아니다 오라클은 밤마다 자동으로 통계를 수집한다. 이 작업의
METHOD_OPT기본값인SIZE AUTO는 "그 컬럼이 WHERE 조건에 쓰인 적이 있는가"를 보고 히스토그램을 만든다.ORD_ST = 'CANCEL'로 한 번이라도 조회하면 그 사실이 기록되고, 그날 밤ORD_ST에 FREQUENCY 히스토그램(20,000 / 900,000 / 80,000)이 생긴다. 그때부터는 옵티마이저가 건수를 정확히 맞히므로 01화의 "16배 오추정"이 사라진다. (2026-10-05 실측 확인)10화(통계와 히스토그램)에서 배울 현상이 미리 나타난 것이다. 01화는 "옵티마이저가 분포를 모르는 상태"를 전제로 하므로
04_상태복구.sql을 한 번 돌려 되돌리면 된다. 데이터는 건드리지 않는다.
📌
Buffers는 환경에 따라 5,826~5,827로 한두 블록 흔들린다(세그먼트 헤더, ASSM 비트맵 블록). 자릿수가 같고E-Rows와A-Rows가 16배 차이 나면 정상이다.
01화가 여기에 무엇을 더하나
01화 실습의 00_관통코드_생성.sql이 강도현이 만든 PKG_ORD_STLM 패키지와 정산 결과 테이블 T_ORD_STLM, 채번 테이블 T_STLM_NUM을 추가한다. 그래서 01화 본문에서는 테이블이 16개이고, 이 문서의 검증은 그 전 상태인 14개를 기준으로 한다.
부하 발생기 — PKG_LOAD_DRIVER
15화에서 만들었고, 16화(AWR)와 17화(ASH)가 이것으로 부하를 만든다. 15화의 교훈(바인드 변수, 배열 처리, 에러를 삼키지 않기, 상태 없는 패키지)을 지켜 짠 PL/SQL이다. 설계 이유는 15화
2_파고들기 §12에 있다.
무엇을 하나
한빛유통 6조각의 현재판 리비전을 가중치대로 섞어 돌리는 세션을 N개 만든다. 세션은 셸에서 띄운다. 이 DB는 job_queue_processes = 1이라서 스케줄러 잡으로는 세션 여러 개를 동시에 띄우지 못한다.
| 조각 | 현재판(평소) | 나쁜 판(SPIKE 구간 · SPIKE_KIND) | ASH · AWR의 ACTION |
|---|---|---|---|
| Q1 월 조회 | rev03(03화 · 바인드 :p_ym). 36개월 중 하나 | — | Q1 rev03 |
| Q2 등급별 집계 | rev01(06화 · 해시 조인) | NL: rev00 LEADING(o c) USE_NL(c)(06화 · 100만 번 왕복) | Q2 rev01 · Q2 rev00 |
| Q3 상품 TOP 5 | rev01(08화 · EXISTS) | — | Q3 rev01 |
| Q4 정산 목록 | rev03(11화 · 포스트잇 바인드). 첫 페이지 30% · 다음 페이지 60% · 날짜로 가기 10% | LIT: 포스트잇을 문장에 이어 붙인 판(11화 개발팀 · 클릭마다 하드 파싱) | Q4 rev03 · Q4 lit |
| N1 정산 등록 | rev01(12화 · 시퀀스). T_STLM_REG_LD에 쓴다 | LOCK: 채번 테이블 FOR UPDATE(12화 핫픽스) + 세션 1이 번호 행을 HOLD_SEC초씩 쥔다(12화 보정 배치) | N1 rev01 · N1 hotfix · N1 hold |
| P1 정산 적재 | rev02(14화 · TRUNCATE + APPEND). 세션별 T_STLM_S<n>_LD에 쓴다 | LOOP: rev00(커서 루프 · 1,000건 커밋) | P1 rev02 · P1 rev00 |
- 모든 세션:
MODULE = 'LOAD_DRIVER'· 생각하는 동안ACTION = 'think'·CLIENT_IDENTIFIER = 'LD<런>-S<세션>'·CLIENT_INFO = 'PKG_LOAD_DRIVER run <런> session <세션>' - 원본에는 한 줄도 쓰지 않는다. 읽기만 하는 테이블은
T_ORD_BIG,T_ORD,T_ORD_DET,T_ITM_EVL,M_CUS이고, 쓰는 곳은 드라이버 전용*_LD테이블뿐이다. 원본 지문은V_LD_FINGERPRINT로 확인한다. - AWR 스냅샷은 찍지 않는다(16화가 찍는다). 대신
T_LD_RUN.STARTED_AT · ENDED_AT이 남는다.
설치 (한 번 · 멱등)
bash
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 05_PKG_LOAD_DRIVER.sqlpowershell
Get-Content 05_PKG_LOAD_DRIVER.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1기대 결과: [2]는 처음 설치하면 created 셋, 다시 설치하면 kept 셋이다(설치해도 지난 런 기록은 지워지지 않는다). 이어서 [3] No errors., [5] 무효 객체 0개, 원본 지문이 나온다. ⚠️ 드라이버가 도는 동안에는 다시 설치하면 안 된다. 돌고 있는 세션들이 패키지를 쥐고 있어서 설치 세션이 library cache pin으로 기다린다. 먼저 STOP_RUN을 보내고 남은 세션이 0개인지 확인한 뒤 설치한다.
돌리기
bash
# Git Bash — 인자는 '이름=값' 환경 변수 (안 주면 기본값)
PROFILE=STEADY MINUTES=3 SESSIONS=2 ./05_부하_돌리기.sh
PROFILE=SPIKE MINUTES=3 SESSIONS=2 SPIKE_AT=1 SPIKE_LEN=1 ./05_부하_돌리기.sh
PROFILE=SPIKE MINUTES=60 SESSIONS=3 SPIKE_AT=30 SPIKE_LEN=5 SPIKE_KIND=NL ./05_부하_돌리기.shpowershell
.\05_부하_돌리기.ps1 -LoadProfile STEADY -Minutes 3 -Sessions 2
.\05_부하_돌리기.ps1 -LoadProfile SPIKE -Minutes 3 -Sessions 2 -SpikeAt 1 -SpikeLen 1
# 스크립트 실행이 막혀 있으면: powershell -ExecutionPolicy Bypass -File .\05_부하_돌리기.ps1 -Minutes 3PowerShell 판은
$OutputEncoding과 콘솔 입력 인코딩을 스스로 BOM 없는 UTF-8로 맞추고, 끝나면 원래대로 되돌린다. 콘솔이 UTF-8(65001)이면 Windows PowerShell 5.1이 파이프로 넘기는 글 앞에 BOM을 붙이고, 그러면 sqlplus가 첫 줄을 버리기 때문이다(SP2-0734, 15화 실측). 스크립트 파일은 BOM 있는 UTF-8로 저장되어 있다. BOM이 없으면 5.1이 한글 주석을 ANSI로 읽다가 따옴표가 깨진다.
발사기는 다음 순서로 일한다. ① 원본 지문(앞) ② START_RUN ③ sqlplus 세션 N개를 백그라운드로 띄워 세션마다 RUN_SESSION(번호) 실행 ④ 기다림 ⑤ END_RUN ⑥ 런별, 세션별, 조각별, 분별 실행 횟수 ⑦ ASH의 ACTION과 대기 분포 ⑧ 원본 지문(뒤) ⑨ 남은 드라이버 세션(기대값 0). Ctrl+C를 누르면 발사기가 STOP_RUN을 보내고 세션이 스스로 끝나기를 기다린다. 세션은 1초 안팎에 끝나고, 그때 돌던 조각은 마저 끝낸다. 다른 창에서 EXEC PKG_LOAD_DRIVER.STOP_RUN을 보내도 결과는 같다. 15화 시험은 이 방법으로 했다.
인자
| 발사기 (.sh / .ps1) | START_RUN 인자 | 기본값 | 뜻 |
|---|---|---|---|
PROFILE / -LoadProfile | p_profile | STEADY | STEADY(고른 부하) · SPIKE(고른 부하 + 구간 동안 나쁜 판) |
MINUTES / -Minutes | p_minutes | 10 | 런 시작부터 이 시간이 지나면 세션이 스스로 끝난다(1 ~ 240) |
SESSIONS / -Sessions | p_sessions | 2 | 세션 수(1 ~ 8). CPU가 2개라서 2 ~ 4 권장 |
THINK_MS / -ThinkMs | p_think_ms | 200 | 조각 사이에 쉬는 평균 ms(실제로는 0.5 ~ 1.5배로 흔든다. 0이면 쉬지 않는다) |
WEIGHTS / -Weights | p_weights | Q1=30,Q2=5,Q3=10,Q4=40,N1=14,P1=1 | 조각 가중치(비율). 0이면 그 조각은 고르지 않는다 |
SEED / -Seed | p_seed | 15 | 세션 k의 씨앗 = p_seed × 1000 + k |
SPIKE_AT / -SpikeAt | p_spike_at | 1 | SPIKE 시작 시점(런 시작 기준 분 · 소수 가능) |
SPIKE_LEN / -SpikeLen | p_spike_len | 1 | SPIKE 길이(분) |
SPIKE_KIND / -SpikeKind | p_spike_kind | NL,LIT,LOCK | NL · LIT · LOCK · LOOP를 쉼표로 이어 쓴다 |
SPIKE_WEIGHTS / -SpikeWeights | p_spike_weights | (없음 = WEIGHTS) | SPIKE 구간에만 쓸 가중치 |
HOLD_SEC / -HoldSec | p_hold_sec | 10 | LOCK 구간에 세션 1이 번호 행을 한 번에 쥐고 있는 시간(초) |
P1_ROWS / -P1Rows | p_p1_rows | 100000 | P1이 한 번에 적재할 행 수(rev02의 p_limit) |
NOTE / -Note | p_note | — | 런 기록에 남길 메모 |
C / -Container | — | ora-hanorder | 컨테이너 |
SQL로 직접 부를 때는 다음과 같다.
sql
EXEC PKG_LOAD_DRIVER.START_RUN(p_profile => 'SPIKE', p_minutes => 3, p_sessions => 2, p_spike_at => 1, p_spike_len => 1)
EXEC PKG_LOAD_DRIVER.RUN_SESSION(1) -- 세션마다 번호만 다르게 (다른 sqlplus 세션에서)
EXEC PKG_LOAD_DRIVER.STOP_RUN -- 아무 세션에서나 — 모든 세션이 다음 판에서 스스로 끝난다
EXEC PKG_LOAD_DRIVER.END_RUN -- 끝 시각 기록 · 작업 테이블 비우기 · 요약 (세션이 남아 있으면 STOP 하고 60초까지 기다린다)
EXEC PKG_LOAD_DRIVER.PURGE_LOG(0) -- 기록 지우기 (최근 n 런을 남긴다)
SELECT PKG_LOAD_DRIVER.LAST_RUN FROM dual; -- 가장 최근 런 번호프로필
| 프로필 | 정의 |
|---|---|
| STEADY | 처음부터 끝까지 6조각의 현재판을 WEIGHTS대로 돌린다. 세션마다 조각을 고르는 순서는 씨앗으로 고정된다 |
| SPIKE | STEADY와 같다. 다만 SPIKE_AT분부터 SPIKE_LEN분 동안은 SPIKE_KIND에 든 조각을 나쁜 판으로 돌리고, SPIKE_WEIGHTS가 있으면 그 가중치를 쓴다. LOCK이면 그 구간에 세션 1은 조각을 돌리지 않고 번호 행을 HOLD_SEC초씩 쥐었다 놓기를 되풀이한다(12화의 보정 배치, ACTION = 'N1 hold'). 쉬는 동안의 대기인 PL/SQL lock timer는 Idle이라서 ASH에는 기다리는 쪽만 찍힌다 |
기록 — 16 · 17화가 AWR · ASH 숫자와 대조하는 곳
| 객체 | 한 줄 = | 칸 |
|---|---|---|
T_LD_RUN | 런 하나 | RUN_ID · 인자 전부 · STATUS(RUN · STOP · DONE · ABORTED) · STARTED_AT · ENDED_AT · CLOSED_AT · NOTE |
T_LD_SESS | 런 × 세션 | SID · SERIAL# · BEGAN_AT · ENDED_AT · EXECS · ERRS · EXIT_REASON(DEADLINE · STOP · TOO_MANY_ERRS · ERR-4068 …) |
T_LD_LOG | 런 × 세션 × 분 × 조각 × 판 | EXECS · ELA_CS · CPU_CS · ERRS · LAST_ERR. 분이 바뀔 때마다 FORALL로 한 번에 적는다 |
V_LD_PIECE | 런 × 조각 × 판 | 합계 · 평균 ms |
V_LD_MINUTE | 런 × 분 × 조각 × 판 | SPIKE 구간이 보이는 곳 |
V_LD_FINGERPRINT | 원본 테이블 하나 | 행수 · 합계 · 세그먼트 블록. 런 앞뒤로 같아야 한다 |
- 에러는 삼키지 않는다. 조각마다 에러를 잡아
ERRS와LAST_ERR에 기록한다. 패키지 재설치나 세션 강제 종료 계열(ORA-04068, 04061, 04065, 06508, 00028, 01013)이면 세션을 끝내고, 20번 연속으로 실패해도 끝낸다. - 작업 테이블(
T_STLM_REG_LD,T_STLM_S1_LD~S8_LD,T_STLM_NUM_LD)은START_RUN이 비우고END_RUN이 다시 비운다.
검증 (15화 실측 · 2세션 × 3분 · THINK_MS 200 · SEED 15)
| STEADY | SPIKE 1분째부터 1분 · NL,LIT,LOCK | SPIKE 1분째부터 1분 · NL,LIT · SPIKE_WEIGHTS=Q1=10,Q2=40,Q3=5,Q4=40,N1=5,P1=0 | |
|---|---|---|---|
| 세션 실행 · 에러 | 873 · 878 · 0 | 587 · 656 · 0 | 776 · 782 · 0 |
| 0분째 Q1·Q2·Q3·Q4·N1·P1 | 168·19·69·243·79·8 | 같다 | 같다 |
| SPIKE 분 | — | Q2 rev00 7 · Q4 lit 21 · N1 hotfix 7(평균 6.2초 대기) · N1 hold 6 | Q2 rev00 152 · Q4 lit 159 |
ASH (MODULE = 'LOAD_DRIVER') | 9샘플(Q2 rev01 4 · P1 rev02 3 …) | N1 hotfix 43 = enq: TX - row lock contention | Q2 rev00 39 = 전부 ON CPU |
| 원본 지문 앞 = 뒤 · 남은 세션 | 같다 · 0 | 같다 · 0 | 같다 · 0 |
- STOP 시험(3세션 ·
SPIKE_KIND=LOCK· 런 18초째): 보내기 직전V$SESSION을 보면 S1은ACTION = 'N1 hold'·PL/SQL lock timer, S2와 S3은ACTION = 'N1 hotfix'·enq: TX - row lock contention·BLOCKING_SESSION = S1이었다(블로킹 체인).STOP_RUN을 보내자 1초 안에 세 세션 모두EXIT_REASON = STOP으로 끝났고, 쥐고 있던 번호 행도 놓았다. 남은 세션은 0개였다. - PowerShell 발사기로도 결과가 같았다(1분 STEADY · 2세션 · 에러 0 · 지문 불변 · 남은 세션 0). 다만
Start-Job이 뜨는 데 1~2초가 걸려서 0분째 실행 수가 Git Bash 판보다 조금 적다. - 씨앗이 같으면 0분째는 런마다 같다. 조각 순서는 결정적이고, 몇 번째 조각까지 가는지는 시간이 정한다.
THINK_MS200인 STEADY는 가볍다(2세션 3분에 ASH 9샘플). AWR에 더 뚜렷하게 남기려면THINK_MS를 줄이거나SESSIONS를 늘린다.- 2세션으로
LOCKSPIKE를 돌리면 세션 1이 행을 쥐고 세션 2가 기다리느라 다른 나쁜 판은 거의 돌지 않는다. CPU 폭발을 보려면SPIKE_KIND=NL에 Q2를 키운SPIKE_WEIGHTS를, 블로킹 체인은SPIKE_KIND=LOCK에SESSIONS=3~4를, 하드 파싱은SPIKE_KIND=LIT에 Q4를 키운SPIKE_WEIGHTS를 쓴다.
16화가 쓴 런 (NOTE로 구분 · AWR 스냅샷은 16화 실습/02가 찍는다)
NOTE | 명령 (이 폴더에서 · Git Bash) | 쓰는 곳 |
|---|---|---|
C16-A · C16-B | PROFILE=STEADY MINUTES=12 SESSIONS=3 THINK_MS=0 NOTE=C16-A ./05_부하_돌리기.sh (B는 NOTE=C16-B) | 16화 구간 A · B(+4분에 보정 배치 한 판) |
C16-H | PROFILE=SPIKE MINUTES=62 SESSIONS=3 THINK_MS=0 SPIKE_AT=31 SPIKE_LEN=5 SPIKE_KIND=LOCK HOLD_SEC=10 SEED=15 NOTE=C16-H ./05_부하_돌리기.sh | 16화의 '한 시간'(AWR 리포트 한 장). 17화가 같은 인자로 다시 연다 |
- ⚠️ 부하 발생기의 Q2는 운영 Q2 rev01과 문장이 다르다.
q2_rev01에는 지역명 스칼라 서브쿼리(MAX((SELECT r.RGN_NM …)))가 없어서 옵티마이저가 Group-by Placement(VW_GBC_)를 적용하고, 실행당 CPU가 운영 문장의 약 1/4이다(16화실습/09실측: 10번 실행에 29cs 대 113cs). 그래서 리포트의 Q2 CPU 몫은 운영보다 작게 나온다. 같은 런을 다시 만들 수 있도록 발생기는 고치지 않았다(바꿀지는 18화에서 정한다). THINK_MS=0에 3세션이면 CPU 2개로는 모자란다. 16화 실측에서 평균 활성 세션은 3.12였고, CPU를 기다린 몫(resmgr:cpu quantum)이 약 25%였다.
17화가 쓴 런 (NOTE로 구분 · 스냅샷은 17화 실습/02 · 08b가 찍는다)
NOTE | 명령 (이 폴더에서 · Git Bash) | 쓰는 곳 |
|---|---|---|
C17-H | PROFILE=SPIKE MINUTES=62 SESSIONS=3 THINK_MS=0 SPIKE_AT=31 SPIKE_LEN=5 SPIKE_KIND=LOCK HOLD_SEC=10 SEED=15 NOTE=C17-H ./05_부하_돌리기.sh (C16-H와 같은 인자) | 17화. 같은 한 시간을 다시 만들어 1초 ASH로 본다(02가 AWR +1 · +61분 · Statspack 5분마다) |
C17-S | PROFILE=STEADY MINUTES=7 SESSIONS=3 THINK_MS=0 NOTE=C17-S ./05_부하_돌리기.sh | 17화 08b(선택). 부하를 건 상태에서 ADDM 권고(시퀀스 캐시)를 적용해 본다 |
- 결과는 결정적이다. 16화의 C16-H와 17화의 C17-H 두 판은 같은 분(31 ~ 35)에 같은 모양이었다(
N1 hold30 × 10초 · 폭발 분의 Q1 15 ~ 31번 · ASH의 10:30 ~ 10:35enq: TX100%). 세션당 실행 수만 장비 속도에 따라 흔들린다. 08b는 드라이버 시퀀스SQ_STLM_LD의 CACHE를 바꿨다가 20으로 되돌린다(05_PKG_LOAD_DRIVER.sql에 적힌 값). 17화99가 한 번 더 확인한다.LOCK구간의 세션 1(N1 hold)은DBMS_SESSION.SLEEP으로 쉬면서 행을 쥐고 있다. Idle 대기라서 ASH에는 한 장도 찍히지 않고, 막힌 쪽 표본의BLOCKING_SESSION에 이름만 남는다. 17화의 한 장면이다.
다시 만들고 싶을 때
두 스키마 스크립트는 맨 앞에서 자기 테이블을 지우고 다시 만든다. 그냥 다시 돌리면 된다. 컨테이너째 초기화하려면 ../../04_일상_운용과_문제해결.md의 "전부 지우고 다시 시작"을 따른다.