Skip to content

L1 · ora-hanorder — ㈜한빛유통 통합주문 HANORDER ★ 본편 무대 ​

포트 1521 · 계정 sqlp / sqlp · 크기 약 95MB · 쓰는 화 01~13, 15 (16화와 17화도 15화가 만든 부하 발생기로 여기서 시작한다) 이 컨테이너 하나만 있으면 01~13화를 진행할 수 있다. 만드는 절차는 ../../01_첫_고객사_ora-hanorder.md에 있다.


이 폴더의 파일 — 번호 순서대로 한 번씩 ​

#파일누가 실행무엇실측
0000_측정권한_부여.sqlSYSsqlp가 실행계획을 볼 수 있게 권한을 준다. 빠뜨리면 ORA-01031이 난다1초
0101_구시스템_스키마A.sqlsqlp구 주문시스템(2015~)의 테이블 6개: DEPT EMP SALGRADE PRODUCTS CUSTOMERS ORDERS5.5초
0202_신시스템_스키마B.sqlsqlp신 주문시스템(2019~, 강도현)의 테이블 8개: M_* 4개 + T_* 4개, T_ORD_BIG 100만 건16.5초
0303_환경검증.sqlsqlp테이블 14개의 행수 · 공간 · 무인덱스 · 첫 실행계획 한 장 판정3초
0404_상태복구.sqlsqlp하루가 지나 E-Rows가 틀어졌을 때 01화의 전제 상태로 되돌린다(필요할 때만)3초
0505_PKG_LOAD_DRIVER.sql · 05_부하_돌리기.sh · 05_부하_돌리기.ps1sqlp부하 발생기(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_환경검증.sql
powershell
# 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 / SALGRADE4 / 14 / 5오라클 고전 예제 SCOTT. 개념 확인, 소량 조인용
PRODUCTS2,000상품
CUSTOMERS20,000고객. grade A 1% / B 9% / C 90%
ORDERS200,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_RGN8지역 코드
M_ITM100상품
M_ITM_PRC_HIS100가격 이력. (ITM_ID, TO_YMD)로 최신 1건을 찾는 조회의 소재
M_CUS2,000고객. CUS_GD A 1% / B 9% / C 90%. CUS_ID가 VARCHAR2('CUS_000123')
T_ORD100,000주문
T_ORD_DET200,000주문상세(주문당 1~3건)
T_ITM_EVL5,000상품평가. M:1:M 조인 폭증(08화) 재현용
T_ORD_BIG1,000,000PK도 인덱스도 없다. 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으로 나오면 내 데이터는 교재와 한 바이트도 다르지 않다.

DEPT4M_RGN8
EMP14M_ITM100
SALGRADE5M_ITM_PRC_HIS100
PRODUCTS2,000M_CUS2,000
CUSTOMERS20,000T_ORD100,000
ORDERS200,000T_ORD_DET200,000
T_ORD_BIG1,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 5rev01(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.sql
powershell
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_부하_돌리기.sh
powershell
.\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 3

PowerShell 판은 $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 / -LoadProfilep_profileSTEADYSTEADY(고른 부하) · SPIKE(고른 부하 + 구간 동안 나쁜 판)
MINUTES / -Minutesp_minutes10런 시작부터 이 시간이 지나면 세션이 스스로 끝난다(1 ~ 240)
SESSIONS / -Sessionsp_sessions2세션 수(1 ~ 8). CPU가 2개라서 2 ~ 4 권장
THINK_MS / -ThinkMsp_think_ms200조각 사이에 쉬는 평균 ms(실제로는 0.5 ~ 1.5배로 흔든다. 0이면 쉬지 않는다)
WEIGHTS / -Weightsp_weightsQ1=30,Q2=5,Q3=10,Q4=40,N1=14,P1=1조각 가중치(비율). 0이면 그 조각은 고르지 않는다
SEED / -Seedp_seed15세션 k의 씨앗 = p_seed × 1000 + k
SPIKE_AT / -SpikeAtp_spike_at1SPIKE 시작 시점(런 시작 기준 분 · 소수 가능)
SPIKE_LEN / -SpikeLenp_spike_len1SPIKE 길이(분)
SPIKE_KIND / -SpikeKindp_spike_kindNL,LIT,LOCKNL · LIT · LOCK · LOOP를 쉼표로 이어 쓴다
SPIKE_WEIGHTS / -SpikeWeightsp_spike_weights(없음 = WEIGHTS)SPIKE 구간에만 쓸 가중치
HOLD_SEC / -HoldSecp_hold_sec10LOCK 구간에 세션 1이 번호 행을 한 번에 쥐고 있는 시간(초)
P1_ROWS / -P1Rowsp_p1_rows100000P1이 한 번에 적재할 행 수(rev02의 p_limit)
NOTE / -Notep_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대로 돌린다. 세션마다 조각을 고르는 순서는 씨앗으로 고정된다
SPIKESTEADY와 같다. 다만 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) ​

STEADYSPIKE 1분째부터 1분 · NL,LIT,LOCKSPIKE 1분째부터 1분 · NL,LIT · SPIKE_WEIGHTS=Q1=10,Q2=40,Q3=5,Q4=40,N1=5,P1=0
세션 실행 · 에러873 · 878 · 0587 · 656 · 0776 · 782 · 0
0분째 Q1·Q2·Q3·Q4·N1·P1168·19·69·243·79·8같다같다
SPIKE 분—Q2 rev00 7 · Q4 lit 21 · N1 hotfix 7(평균 6.2초 대기) · N1 hold 6Q2 rev00 152 · Q4 lit 159
ASH (MODULE = 'LOAD_DRIVER')9샘플(Q2 rev01 4 · P1 rev02 3 …)N1 hotfix 43 = enq: TX - row lock contentionQ2 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_MS 200인 STEADY는 가볍다(2세션 3분에 ASH 9샘플). AWR에 더 뚜렷하게 남기려면 THINK_MS를 줄이거나 SESSIONS를 늘린다.
  • 2세션으로 LOCK SPIKE를 돌리면 세션 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-BPROFILE=STEADY MINUTES=12 SESSIONS=3 THINK_MS=0 NOTE=C16-A ./05_부하_돌리기.sh (B는 NOTE=C16-B)16화 구간 A · B(+4분에 보정 배치 한 판)
C16-HPROFILE=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_부하_돌리기.sh16화의 '한 시간'(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-HPROFILE=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-SPROFILE=STEADY MINUTES=7 SESSIONS=3 THINK_MS=0 NOTE=C17-S ./05_부하_돌리기.sh17화 08b(선택). 부하를 건 상태에서 ADDM 권고(시퀀스 캐시)를 적용해 본다
  • 결과는 결정적이다. 16화의 C16-H와 17화의 C17-H 두 판은 같은 분(31 ~ 35)에 같은 모양이었다(N1 hold 30 × 10초 · 폭발 분의 Q1 15 ~ 31번 · ASH의 10:30 ~ 10:35 enq: TX 100%). 세션당 실행 수만 장비 속도에 따라 흔들린다.
  • 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의 "전부 지우고 다시 시작"을 따른다.