테마
T6 — 사내 튜닝 표준 v1.0
18화에 제정했다(7월 8일 월요일 · ㈜한빛유통 튜닝팀). 조문 열여섯 개와 코드 리뷰 체크리스트, 마지막 조항 하나로 이루어진다. 승격 규칙: 지금까지의 리포트에서 두 번 이상 나온 원인만 조문이 된다. 표준을 정하는 것은 저자의 취향이 아니라 리포트다. 한 번만 나온 원인은 버리지 않는다. 대기 줄(§2)에 세워 두고, 같은 원인이 한 번 더 나오면 그날 조문으로 올린다. 이 표준은 T0 측정규약을 고치지 않는다. T0는 "무엇으로 재는가"(Buffers N → M)를 정했고, T6은 "그 숫자 옆에 무엇을 함께 적는가"를 정한다.
0. 이 표준은 어떻게 만들어졌나
원천 — 18주 동안 쓴 리포트
| 양식 | 번호 (화) |
|---|---|
| T1 단건 SQL | 1호 (02) · 2호 (03) · 3호 (05) · 4호 (06) · 5호 (07) · 6호 (08) · 7호 (09) · 8호 (10) · 9호 (11) · 10호 = T4 2호 (13) · 11호 (15b) · 12호 · 13호 (18) |
| T2 승인서 | T2-001 (04) · T2-002 (04 → 14 → 16 → 18) |
| T3 배치 SLA | 1호 (14) · 2호 (15) · 3호 (18) |
| T4 포스트모템 | 1호 (12) · 2호 (13) |
| T5 시스템 | T5-001 (16) · T5-002 (17) · T5-003 (18) |
| T7 · T8 | T7 1호 (16) · 2호 (17) · 3호 (18) · T8 1호 (16) |
| 그 밖 | 03화 정합성 이상 보고 · 힌트 유효기간 대장 1호 (06) · 화면 요구 재협상서 1호 (09) · 통계 수집 정책서 1 · 2호 (10) |
승격 절차
- 리포트마다 원인 칸에 적힌 말을 그대로 뽑는다(원인 칸이 비어 있으면 그 화 본문의 말을 쓴다).
- 같은 원인끼리 묶는다. 겉모양(조각 · 화면 · 장비)이 아니라 무엇 때문에 틀렸나로 묶는다.
- 서로 다른 리포트 둘 이상에서 나왔으면 조문, 하나뿐이면 §2 대기 줄에 둔다.
- 조문마다 각주를 세 개 단다: [근거 리포트], [성능고도화 권-장-절], [공식문서 매뉴얼-장]. 원천 좌표는 그 리포트를 쓴 화의
2_파고들기「원천 좌표」 절에 이미 적힌 것만 옮긴다(18화의 몫인 SPM · SQL Tuning Advisor는원천지도/오라클공식문서_지도.md의 18화 줄에서 옮긴다). 거기에도 없으면 「좌표 미확인」이라고 쓴다(지어내지 않는다). 각주에서 좌표 옆 괄호 안의 숫자는 그 좌표를 적은 화다.
승격 판정표 (요약)
| 원인 | 리포트 | 횟수 | 판정 |
|---|---|---|---|
| 결정 · 보고에 그때의 규모와 근거 수치가 없다 · 전제를 적지 않아 결정이 유효기간을 넘겼다 | T2-001 · T1 4호 · 대장 1호 · T1 6호 · T1 7호 · T1 8호 · T4 1호 · T1 11호 · T1 12호 | 9 | 마지막 조항 |
| 한 칸 · 한 비율 · 한 평균을 결론으로 썼다 | T1 5호 · T5-001 · T8 1호 · T5-002 | 4 | 제1조 |
| Buffers로는 안 보이는 것(TEMP · CPU · 정답 · 시계)이 회귀했다 | T1 4호 · T1 5호 · T1 6호 · T1 7호 · T1 11호 · T1 12호 | 6 | 제2조 |
| 측정 조건 · 부하 모델이 운영과 달랐다 | T1 5호 · T1 9호 · T3 1호 · T7 1호 · T5-001 · T3 2호 | 6 | 제3조 |
| 컬럼을 가공해 인덱스 · 통계를 잃었다 | T1 1호 · T1 2호 | 2 | 제4조 |
| '이 데이터에서 같다'를 '맞다'로 읽었다 | T1 1호 · T1 2호(+정합성 이상 보고) · T1 6호 · T3 2호 · T1 11호 | 5 | 제5조 |
| 행마다 건너가는 일(왕복 · 래치 · 재귀 호출 · 함수)의 횟수 | T1 4호 · T1 5호 · T3 1호 · T3 2호 | 4 | 제6조 |
| 통계 상태가 계획을 정했다 | T1 8호 · T3 1호 · T1 9호 | 3 | 제7조 |
| 처방을 패턴이 아니라 모양으로 옮겼다 (커밋 · 채번 · 배치) | T4 1호 · T4 2호 · T3 1호 · T3 2호 | 4 | 제8조 |
| 서버 스위치 · 자원 증설로 덮자는 제안 | T1 7호 · T1 9호 · T5-001 | 3 | 제9조 |
| 도구의 권고를 근거 칸 없이 따르려 했다 | T5-001 · T5-002 · T1 13호 | 3 | 제10조 |
| 리스크 칸이 비었거나, 그 일을 할 사람이 안 읽는 곳에 적혔다 | T4 1호 → T4 2호 · T1 7호 → T1 9호 | 4 (사슬 둘) | 제11조 |
| 바꾸는 것의 영향 범위를 안 봤다 (카디널리티 · 적재 순서 · 보관 정책 · 버그 수정) | T1 6호 · T4 1호 · T2-001 · T1 3호 | 4 | 제12조 |
| 요구를 다시 묻지 않았다 | T1 7호(+재협상서 1호) · T4 1호 | 2 | 제13조 |
| 에러 없이 사라진 것 (삼킨 예외 · 반쯤 반영) | T3 2호 · T4 2호 · T3 1호 | 3 | 제14조 |
| 인자로 들어오지 않는 입력 (NLS · 시계 · 세션) | T1 2호 · T1 11호 | 2 | 제15조 |
| 팩 계약 · 팩 설정에 기대는 도구와 해결책 | T5-002 · T1 13호 | 2 | 제16조 |
18화의 리포트(T1 12 · 13호 · T5-003 · T3 3호)도 근거로 센다. 18화도 리포트를 쓴 날이기 때문이다. 다만 18화 리포트 하나만으로 올린 조문은 없다(제2 · 10 · 16조는 앞 화의 리포트가 먼저 있었다).
1. 조문
제1조 한 칸으로 결론을 내지 않는다
리포트의 한 칸, 한 비율, 한 평균은 결론이 아니다. 다른 칸에서도 같은 사실이 확인될 때까지 대조한다.
- 비율(히트율 · Execute to Parse % …) 옆에는 분자와 분모의 초당 값을 같이 적는다.
- 시간을 나타내는 숫자에는 세 질문의 답을 붙인다. 평균인가, 횟수인가, 언제인가(진단 도구 4열 대응표에서 그 질문에 답하는 칸을 고른다).
- 한 시간짜리 평균으로 현업이 말한 '몇 분'을 기각하지 않는다. 평균은 '언제'를 본 뒤에만 쓴다(세칙 · 17화 T5-002).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T1 5호 (07화 · 히트율 99.89 → 80.17%, 물리 읽기 11,626 = 11,626) · T5-001 (16화 · Buffer Hit 99.99% · CPU 2.01 · Elapsed 1위, 셋 다 다른 칸과 어긋남) · T8 1호 (16화 · 고쳤더니 Execute to Parse 73.05 → 63.28) · T5-002 (17화 · enq: TX 한 칸 5.5% · 5분 칸 100%) | I권 03장 05절 Ratio 기반 분석 (p.194 ~ 198 · 16화) · 08절 Statspack / AWR (p.210 · 212 · 214 · 16 · 17화) · 09절 ASH (p.220 ~ 224 · 17화) · I권 「버퍼 캐시 히트율」 (p.441 · 07화) | tgdba Gathering Database Statistics (Automatic Workload Repository) (16화) · tgdba Analyzing Sampled Data (17화) · tgdba Tuning the Database Buffer Cache (07화) |
제2조 Buffers로 안 보이는 값은 같은 조건으로 함께 적는다
T0의 판정 기준은 Buffers N → M이다. 그런데 Buffers가 같거나 이미 바닥인데도 바뀐 것(TEMP 패스 · CPU · 결과 · 시각)이 있다면, 그 값을 같은 조건으로 재서 옆에 적는다.
- CPU는 같은 세션, 같은 데이터로 데우기를 한 뒤 10회 합을 세 번 잰다(한 번 잰 초는 증거가 아니다).
- 그 SQL이 시스템에서 차지하는 몫(T5 · AWR)이 함께 있을 때만 CPU를 채택 근거로 쓴다(18화 T1 12호 · Q2 rev02).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
| T1 4호 (06화 · Buffers 5,869 / 5,868 · 0.17 → 7.7초, 책상이 좁아지면) · T1 5호 (07화 · rev01의 CPU 절반이 스칼라 캐시 탐색) · T1 6호 (08화 · 839 → 839 · 금액 50배) · T1 7호 (09화 · 64KB 책상 184 PASSES) · T1 11호 (15b화 · 계획 · Buffers · 해시 셋 다 같은데 정산일이 멈춤) · T1 12호 (18화 · 5,868 → 5,868 · CPU 115 → 33cs) | II권 Ch2 03절 해시 조인 (p.249 ~ 264 · 06화) · II권 Ch5 01절 소트 (p.572 ~ 580 · 09화) | tgdba Tuning the Program Global Area (09화) · tgdba Tuning the Database Memory (PGA Memory Management) (06화) |
제3조 측정 조건과 부하 모델을 적고, 운영과 다른 점을 적는다
연습 DB의 숫자는 그 조건에 따라 달라진다. 캐시 상태, statistics_level, 부하 발생기의 문장, 세션 수, 장비가 모두 조건이다. 다른 점을 적지 않은 측정은 증거가 아니다.
- 시스템 리포트(T5)는 워크로드 프로파일 ID(T7)가 없으면 무효다.
- 연습 DB의 초를 운영의 초로 옮기지 않는다(T3의 규칙을 모든 리포트에 적용한다).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T1 5호 (07화 · 같은 SQL의 히트율이 캐시 상태에 따라 1% ~ 100%) · T1 9호 (11화 · statistics_level = ALL로 재자 ACS가 고쳐졌다. TYPICAL에서는 아니다) · T3 1호 (14화 · 연습 DB 329초) · T7 1호 (16화 · 발생기의 Q2는 운영 문장이 아니었다) · T5-001 (16화) · T3 2호 (15화 · 연습 DB의 1/8은 운영의 1/8이 아니다) | I권 03장 「오라클 성능 관리」 (p.153 · 16화) | tgdba Performance Improvement Methods (01화) · tgdba Measuring Database Performance (01 · 16화) |
제4조 컬럼을 가공하지 않는다
형변환과 함수는 리터럴 · 바인드 쪽에서 처리한다. 컬럼을 가공하면 인덱스와 통계를 함께 잃는다. SQL을 고칠 수 없으면 함수 기반 인덱스나 가상 컬럼을 쓴다(T2를 거친다).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T1 1호 (02화 · TO_CHAR(ORD_DT): 힌트를 줘도 FULL 5,826 · E-Rows 2,500) · T1 2호 (03화 · 숫자 리터럴과 비교한 문자 컬럼 5 → 1,406 · 날짜가 VARCHAR2(8)) | II권 Ch1 03절 「인덱스 사용이 불가능한 경우」 · 04절 「함수 기반 인덱스 · 가상 컬럼」 (02 · 03화) | tgsql Optimizer Access Paths (02화) · sqlrf Data Type Comparison Rules (03화) |
제5조 '이 데이터에서 같다'를 '맞다'로 읽지 않는다
고친 SQL은 원장(업무 정의를 가장 단순하게 쓴 SQL)과 대조하고, 경계 데이터를 복사본에 만들어 대조한다(정합성 회귀 체크리스트 A~H). 직전 판과만 대조하면 직전 판이 빠뜨린 것은 끝내 보이지 않는다.
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T1 1호 (02화 · T_ORD_BIG은 전부 자정이라 BETWEEN이 통과 · T_ORD에서 137건 34,159,700원) · T1 2호 + 정합성 이상 보고 (03화 · 0 패딩 누락 36,290건 / 297,291,000원) · T1 6호 (08화 · 평가 수가 다 50이라 순위가 같았다 · 금액 50배) · T3 2호 (15화 · 직전 판과 대조하면 99,850 = 99,850으로 '통과' · 원장과 대조하니 170건) · T1 11호 (15b화 · 같은 날 오후의 대조 100,000 = 100,000 · 경계 시각에서 100,001 vs 100,000) | II권 Ch4 01절 「쿼리 변환이란」 (p.462) · 02절 「서브쿼리 Unnesting」 (p.466 · 08화) | tgsql Query Transformations (08화) |
제6조 행마다 건너가는 일은 횟수로 적는다
한 번의 값이 작아도 횟수 × 한 번만큼 시간이 든다. NL의 Starts, 스칼라 서브쿼리, 루프 안의 SQL, 행마다 호출하는 함수, 클릭마다 일어나는 하드 파싱이 그렇다. 리포트에 횟수를 적는다(Starts · recursive calls · 함수 본문 실행 수 · parse count).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T1 4호 (06화 · inner Starts 1,000,000 · 1,026,849 → 5,869) · T1 5호 (07화 · CBC 래치 1,035,706번 · 고객명 스칼라 Starts 752,995) · T3 1호 (14화 · 인덱스 셋을 행마다 · redo 916.6MB) · T3 2호 (15화 · recursive calls 301,187 → 2,457 · 함수 100,020 → 2,000) | II권 Ch2 01절 NL 조인 (p.210 · 06화) · I권 05장 Call 통계 · User Call vs Recursive Call (p.346 · 349 · 09 · 15화) · I권 「PL/SQL 함수의 특징과 성능 부하」 (p.392 · 15화) | tgsql Joins (06화) · lnpls PL/SQL Optimization and Tuning (15화) |
제7조 통계는 관리하는 설정이다 — 그리고 계획은 지킬 수 있다
옵티마이저는 데이터가 아니라 통계를 본다. 통계를 누가 · 언제 · 무엇으로 모으는지 통계 수집 정책서에 적는다. 적재나 통계가 바뀌어도 계획이 흔들리면 안 되는 문장은 SQL Plan Baseline으로 지키고, 새 계획은 EVOLVE(실행 검증)를 통과한 뒤에만 받아들인다(18화 실측: 빈 테이블 통계에서도 HASH 5,868 유지 · 베이스라인을 끄면 NL 1026K · 그 NL은 진화에서 0.33배로 탈락).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T1 8호 (10화 · 빈 테이블 통계 → Q2 5,868 → 1,026,852 · Q1 91 → 27,274) · T3 1호 (14화 · APPEND 온라인 통계는 히스토그램을 모으지 않는다: FREQUENCY → NONE) · T1 9호 (11화 · 히스토그램 + 바인드 · FORCE가 첫 손님 값으로 계획을 묶었다) | II권 Ch3 03절 「옵티마이저의 한계」 (p.385 ~ 387) · 08절 「통계정보 II」 (p.442 ~ 459 · 10화) | tgsql Optimizer Statistics Concepts (10 · 14화) · tgsql SQL Plan Management (장) · arpls DBMS_SPM (원천지도 18화 줄) |
제8조 처방은 코드의 모양이 아니라 패턴으로 고른다
같은 처방(N건마다 COMMIT, 채번 테이블, 한 문장으로)도 한 배치에서는 안전하고 다른 배치에서는 장애가 된다. 읽기와 쓰기를 떼어 놓는다. 채번은 업무 트랜잭션에서 떼고, 긴 커서는 그 커서가 읽는 테이블의 커밋에서 뗀다. 커밋은 커밋 주기 기준의 경로 번호로 적는다.
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
| T4 1호 (12화 · 강도현이 접어 둔 채번 테이블을 다시 펼쳤다 · 316~321cs 대기) · T4 2호 = T1 10호 (13화 · '트랜잭션을 짧게'를 읽으면서 고치는 배치에 적용 → ORA-01555 · 반쯤 반영) · T3 1호 (14화 · P1 1,000건 커밋 → 화면에 정산이 반만 보임) · T3 2호 (15화 · 12화 처방을 그대로 얹은 보정 배치) | I권 02장 「일련번호 채번 동시성 높이기」 (p.122) · Enqueue Lock · TX Lock (p.126 · 130 · 12화) · I권 Ch1 후반 Undo · 블록 클린아웃 · CR (p.41 · 46 · 54 · 58 · 13화) | cncpt Data Concurrency and Consistency (12 · 13화) · sqlrf COMMIT (13화) |
제9조 서버 스위치 · 자원 증설 제안에는 "무엇을 재 보라"로 답한다
PGA, CPU, CURSOR_SHARING, 바인드 피킹 같은 인스턴스 스위치는 어느 문장이 그 덕을 보고 어느 문장이 망가지는지 가리지 못한다. 제안이 오면 ① 그 설정으로 줄어드는 몫(예: CPU를 기다린 % DB time)을 먼저 재고, ② 내 세션에서만 켜서 일부러 계획을 갈라 둔 문장을 찾아 잰다.
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
| T1 7호 (09화 · PGA를 올리면 멈추는 페이지가 뒤로 밀릴 뿐 · Buffers 5,826 그대로) · T1 9호 (11화 · FORCE: 취소 탭 5,826 → 50,347 · 피킹 끄기: 2페이지 1,005,991) · T5-001 (16화 · CPU를 늘려 줄어드는 것은 CPU 대기 25.1% · 23.8%뿐) | II권 Ch5 07절 「Sort Area 크기 조정」 (p.615 ~ 620 · 09화) · I권 「Cursor_Sharing」 (p.502 · 11화) | tgdba Tuning the Program Global Area (09화) · tgsql Improving Real-World Performance Through Cursor Sharing (11화) · refrn Initialization Parameters (09 · 11 · 16화) |
제10조 도구의 권고는 가설이다
ADDM, SQL Tuning Advisor, SQL 프로파일, 자동 진화가 내놓는 권고문은 검사필증이 아니다. 채택하기 전에 ① 권고가 기댄 칸(Rationale · 시간 모델)을 표본으로 다시 세고, ② 권고를 적용한 뒤 T0로 다시 재고, ③ 그 해결책이 무엇을 숨기는지(코드에 남은 힌트 · 팩 의존 · 계획 고정) 적는다.
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
| T5-001 (16화 · ADDM 요약 1위 Sequence Usage: 근거 줄이 SQL 경과 시간과 230배 어긋남) · T5-002 (17화 · 권고(CACHE 1000)대로 해도 DB time 900.7 → 902.2초 · 같은 권고를 다시 냄 · Row Lock은 Rationale이 ASH와 100% 일치해 채택) · T1 13호 (18화 · STA '예상 이득 99.42%' 프로파일 = 힌트를 무시하라는 두 줄 · 팩을 끄면 1026K로 돌아감 → 기각) | 좌표 미확인 | tgdba Automatic Performance Diagnostics (17화) · tgsql SQL Tuning Advisor (sql-tuning-advisor.html · 원천지도 18화 줄) |
제11조 리스크와 롤백 칸을 비우지 않는다 — 그 일을 할 사람이 읽는 곳에 쓴다
비워 둔 리스크 칸은 다음 장애가 된다. 적었더라도 구현하는 사람이 읽지 않는 문서에만 있으면 비운 것과 같다. 개발자에게는 코딩 가이드와 PR 체크리스트로, 배치 담당에게는 T3의 칸으로 옮긴다.
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
| T4 1호 (12화 · 재발방지 2번 N건마다 COMMIT의 리스크 칸이 비었다) → T4 2호 (13화 · 그 처방이 ORA-01555를 냄) · T1 7호 (09화 · 포스트잇 값을 문자열로 붙이면 페이지마다 다른 SQL: 리스크 칸에 적었다) → T1 9호 (11화 · 개발팀은 리포트가 아니라 실습 스크립트를 베꼈다 · 하드 파싱 30,431) | 좌표 미확인 | 좌표 미확인 |
제12조 바꾸는 것의 영향 범위를 적는다
카디널리티를 바꾸는 변경(PK · 다건 허용 · 코드 재적재), 적재 순서를 바꾸는 이관, 보관 정책, '버그 수정'이라며 공지 없이 나가는 반영이 있으면 그 테이블을 읽는 SQL 전부를 회귀 대상에 올린다(체크리스트 H).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T1 6호 (08화 · 2020-02 평가 다건 허용 커밋에 Q3가 빠졌다) · T4 1호 (12화 · 버그 수정이라는 이유로 동시 시험 · 공지 없이 반영) · T2-001 (04화 · 이관 때 적재 순서가 바뀌어 CF 22,223 → 999,958) · T1 3호 (05화 · 보관을 DELETE로만 처리: 3,602 → 3,602) | II권 Ch1 05절 클러스터링 팩터 (04화) · I권 Ch1 · Ch6 고수위선 (05화) | tgsql Optimizer Access Paths (04화) · cncpt Logical Storage Structures (05화) |
제13조 요구도 늙는다 — 원문을 다시 묻는다
화면, 감사, 마케팅의 요구는 처음 정한 사람이 떠나면 이유도 같이 떠난다. SQL이 요구 때문에 바닥에 붙어 있으면 요구의 원문을 찾아 화면 주인에게 다시 묻는다(화면 요구 재협상서).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
| T1 7호 + 재협상서 1호 (09화 · 아무도 안 보던 총건수 · 11,652 → 약 15) · T4 1호 (12화 · 감사 원문은 '결번 금지'가 아니라 '결번 사유 기록') | I권 05장 「페이지 처리의 중요성」 (p.389 · 09화) | 좌표 미확인 |
제14조 에러 없이 사라지는 것을 센다
WHEN OTHERS THEN NULL, 반쯤 반영된 커밋, 오류 없이 끝난 배치를 경계한다. 정상 종료가 곧 결과가 맞다는 뜻은 아니다. 배치는 원장 = 처리 + 반송이 맞는지 센다. 예외는 사유와 함께 반송함에 남긴다.
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
| T3 2호 (15화 · 에러 로그는 깨끗했는데 170건이 사라짐: 탈퇴 고객 150 · 미확정 20) · T4 2호 (13화 · ORA-01555 시점까지만 반영 50,000 / 50,000) · T3 1호 (14화 · 1,000건마다 커밋하는 동안 화면에 정산이 반만 보임) | 좌표 미확인 | sqlrf INSERT (error_logging_clause) · arpls DBMS_ERRLOG (15화) |
제15조 인자로 들어오지 않는 입력은 인자로 꺼낸다
시계(SYSDATE), 세션 시간대, NLS, 세션 상태에 기대는 코드는 같은 인자에도 다른 답을 낸다. 그런 입력은 인자로 꺼내고, 결과 캐시와 DETERMINISTIC은 답이 테이블과 인자에만 기댈 때만 붙인다.
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T1 2호 (03화 · NLS가 DD-MON-RR이면 27,390건 · YYYY-MM-DD면 에러 없이 1,000,000건) · T1 11호 (15b화 · 결과 캐시가 정산일을 6/14로 고정 · 6/14 17:30 ~ 6/17 09:40) | I권 「Result 캐시」 (p.472) · 「Deterministic 함수 사용 시 주의사항」 (p.512 · 15b화) | lnpls PL/SQL Subprograms (PL/SQL Function Result Cache) · DETERMINISTIC Clause (15b화) · nlspg Setting Up a Globalization Support Environment (03화) |
제16조 팩 라이선스 확인란을 채운다
진단 팩(AWR · ASH · ADDM)이나 튜닝 팩(SQL Monitor · STA · SQL 프로파일)을 쓰는 작업과 리포트에는 에디션 · CONTROL_MANAGEMENT_PACK_ACCESS · 계약 여부를 적는다(§4 서식).
NONE은 막아 주지 않는다. AWR 리포트, ASH 리포트,DBA_HIST_*조회는 그대로 열린다. 라이선스는 설정이 아니라 계약으로 지킨다(17화).- 튜닝 팩이 꺼지면 받아 둔 SQL 프로파일은 에러 없이 무시된다(18화 실측:
DIAGNOSTIC·NONE에서 Q2 rev00이 5,869 → 1026K). 팩에 기대는 해결책은 해결책이라기보다 계약의 일부다. 코드로 고칠 수 있으면 코드로 고친다. SPM 베이스라인은 팩 기능이 아니다(NONE에서도 쓰였다).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
T5-002 (17화 · SE2 서버에서 습관처럼 awrrpt · NONE에서 막힌 것 셋 · 막히지 않은 것 넷) · T1 13호 (18화 · 프로파일이 팩 설정 하나로 사라진다) | 좌표 미확인 | dblic Licensing Information (16 · 17화) · refrn Initialization Parameters: CONTROL_MANAGEMENT_PACK_ACCESS (16 · 17화) |
2. 대기 줄 — 근거 1회 (조문이 아니다 · 다음 재발에 올린다)
| 후보 | 낸 화 | 근거 (1회) | 지금 어디에 남나 | 올라가는 날 |
|---|---|---|---|---|
| 화면이 고르는 값은 바인드로 · 코드값은 상수 리터럴로 · 엿보지 못해도 같은 계획이 나오는 모양 (코딩 가이드 1 ~ 6) | 11 | T1 9호 | 코딩 가이드 v1.0 「대기 조문」 · 체크리스트 A · B | 리터럴 이어 붙이기 · FORCE 제안이 다른 리포트에서 다시 나올 때 |
날짜 범위는 >= 시작 AND < 다음 구간 (가이드 7) | 02 | T1 1호 (03화는 VARCHAR2(8)에서 BETWEEN이 맞는 반례) | 가이드 대기 조문 · 체크리스트 B | 시분초가 있는 날짜의 BETWEEN이 다른 리포트에서 다시 나올 때. 졸업 과제의 ECOMMERCE가 그 후보다 |
| 조인 상대가 그 키로 정말 한 줄인가 (가이드 9) | 08 | T1 6호 | 가이드 대기 조문 · 체크리스트 B (정합성 D) | 1 쪽이 하나가 아닌 조인이 다시 나올 때. 졸업 과제가 그 후보다 |
| 페이징은 키 기반 · 정렬 키는 유일하게 (가이드 10) | 09 | T1 7호 | 가이드 대기 조문 | 깊은 페이지 · 정렬 키 중복이 다시 나올 때 |
적재 방식을 배치 머리에 적는다 · APPEND면 LOAD AS SELECT를 확인한다 | 14 | T3 1호 | T2 v2 「3-2 적재 비용」 · T3 2번 칸에 이미 들어 있다 | — |
FORALL에는 묶이는 문장을 · ERROR_INDEX는 첨자가 아니다 | 15 | T3 2호 | 가이드 대기 조문 | — |
| 한 시간 리포트로 현업의 '몇 분'을 기각하지 않는다 | 17 | T5-002 | 제1조 세칙으로 흡수(원인이 '평균을 결론으로'와 같다) | — |
이관할 때 ORDER BY로 적재 순서를 지킨다 | 04 | T2-001 | 제12조의 예 | — |
| 지난 결론을 지우지 않고 옆에 정정한다 (교차검증판) | 17 | (원인이 아니라 방법) | §5 문서 운용 | 조문이 될 수 없다. 운용 규칙으로 둔다 |
조문을 아끼는 것이 아니다. 두 번 나온 것은 구조이고, 한 번 나온 것은 사건이다. 사건을 조문으로 만들면 표준이 그날의 기분을 따라 자란다.
3. 코드 리뷰 체크리스트 — PR마다 (Y / N / N-A)
리뷰어는 N이 하나라도 있으면 이유 칸을 채우게 하고 머지를 미룬다. N-A는 이유를 같은 칸에 쓴다(빈칸과 다르다).
A. 계획 — 재고 왔는가 (제1 · 2 · 3조)
| # | 묻는 것 | Y | N | N/A |
|---|---|---|---|---|
| A1 | 예상 계획(EXPLAIN PLAN)만이 아니라 실제 실행계획(ALLSTATS LAST)을 첨부했는가 | |||
| A2 | access와 filter를 구분해 적었는가 | |||
| A3 | E-Rows와 A-Rows가 10배 넘게 어긋난 줄을 짚었는가(어긋났다면 통계 정책서 SOP) | |||
| A4 | 효과를 Buffers N → M 형식으로 적었는가 · 그 숫자의 조회 범위(행수 · 선택도)를 옆에 적었는가 | |||
| A5 | Buffers가 같다면 바뀐 값(CPU 10회 합 · TEMP 패스 · 결과)을 같은 조건으로 적었는가 | |||
| A6 | 측정 조건(캐시 · statistics_level · 데이터 규모 · 부하 프로파일 ID)과 운영과 다른 점을 적었는가 |
B. 정합성 — 맞는가 (제5 · 14 · 15조)
| # | 묻는 것 | Y | N | N/A |
|---|---|---|---|---|
| B1 | 원장(업무 정의를 가장 단순하게 쓴 SQL)과 건수 · 합계 · 양방향 MINUS · 중복 키를 대조했는가 | |||
| B2 | 잘라 내기 전(TOP N · 페이징을 뗀) 전체로 대조했는가 | |||
| B3 | 조인마다 '1 쪽'이 그 키로 정말 하나인지 · 1 쪽에 없는 키(고아)가 있는지 봤는가 | |||
| B4 | 경계(시분초 · NULL · 0 패딩 · 시각 · 세션)를 복사본에 만들어 대조했는가 | |||
| B5 | 예외를 삼키지 않는가(WHEN OTHERS THEN NULL 없음) · 배치라면 '원장 = 처리 + 반송'을 확인했는가 | |||
| B6 | 시계 · NLS · 세션 상태에 기대는 곳이 있으면 인자로 꺼냈는가 · 결과 캐시 · DETERMINISTIC이 거짓 약속이 아닌가 |
C. 변경 — 무엇을 바꾸나 (제4 · 7 · 12조)
| # | 묻는 것 | Y | N | N/A |
|---|---|---|---|---|
| C1 | 인덱스 · 힌트를 더하거나 빼면 T2 승인서를 붙였는가(INVISIBLE 먼저 · 적재 비용 3-2 · 손익분기) | |||
| C2 | 힌트를 붙였다면 힌트 유효기간 대장에 그때의 규모와 재검토 조건을 적었는가 | |||
| C3 | 컬럼을 가공하지 않았는가(형변환은 리터럴 · 바인드 쪽) | |||
| C4 | 그 테이블을 읽는 SQL 전부를 회귀 대상에 올렸는가(카디널리티 · 적재 순서 · 통계 · 보관 정책 변경) | |||
| C5 | 계획이 흔들리면 안 되는 문장이면 SPM 베이스라인 · 진화 절차를 적었는가 |
D. 배치 — 창 안에 · 안전하게 (제6 · 8조)
| # | 묻는 것 | Y | N | N/A |
|---|---|---|---|---|
| D1 | 루프 안의 SQL · 행마다 호출하는 함수의 횟수를 적었는가(recursive calls · 함수 본문 실행 수) | |||
| D2 | 커밋 주기를 커밋 주기 기준의 경로 번호로 적었는가 · fetch across commit이 아닌가 | |||
| D3 | 대량 DML의 redo · undo를 재거나 추정했는가(적재 방식과 함께) | |||
| D4 | 낮과 겹치면 무엇이 막히는지(T3 7번) 적었는가 · 리소스 매니저에 기대면 그 장비에서 잰 값인가 |
E. 운영 — 되돌릴 수 있는가 (제11 · 16조 · 마지막 조항)
| # | 묻는 것 | Y | N | N/A |
|---|---|---|---|---|
| E1 | 롤백 절차가 있는가(명령 · 소요 · 되돌릴 수 없는 것) | |||
| E2 | 리스크를 그 일을 할 사람이 읽는 곳(이 PR · 코딩 가이드 · T3)에 적었는가 | |||
| E3 | 진단 · 튜닝 팩을 쓰면 팩 라이선스 확인란을 채웠는가 · 해결책이 팩에 기대지 않는가 | |||
| E4 | 재측정 계획(지표 · 주기 · 사건으로 쓴 재검토 조건)이 있는가 | |||
| E5 | 이 결정에 그 당시의 데이터 규모와 근거 수치가 함께 적혀 있는가 |
4. 팩 라이선스 확인란 (제16조의 서식)
| 항목 | 적는 것 | 18화 연습 DB |
|---|---|---|
| 에디션 | V$VERSION 첫 줄 | Oracle AI Database 26ai Free 23.26.2 |
CONTROL_MANAGEMENT_PACK_ACCESS | 메모리 · spfile 값 | DIAGNOSTIC+TUNING · DIAGNOSTIC+TUNING |
| 계약 | 진단 팩 · 튜닝 팩 계약 여부 | Free: 둘 다 포함 |
| 이 작업이 쓰는 팩 기능 | AWR · ASH · ADDM (진단) / SQL Monitor · STA · SQL 프로파일 (튜닝) | AWR · ADDM · STA · 프로파일 |
| 팩이 꺼지면 이 해결책은 | 막힌다 / 조용히 무시된다 / 상관없다 | 프로파일: 조용히 무시 (Q2 rev00 5,869 → 1026K) · SPM 베이스라인: 상관없다 |
| 팩이 없는 서버라면 | 대신 쓰는 도구 | Statspack · 블로킹 트리 주기 저장 · 코드로 고친다 |
5. 문서 운용 (조문이 아닌 규칙)
| 규칙 | 왜 |
|---|---|
| 지난 결론을 지우지 않고 옆에 정정한다. 1호를 고치지 않고 2호에서 1호의 칸 옆에 정정을 적는다(17화 T5-002 교차검증판 · 18화 W01 2열) | 무엇이 왜 틀렸는지 남아 있어야 다음 사람이 같은 칸에서 같은 결론을 내리지 않는다 |
| 조문의 근거가 된 리포트가 정정되면 그 조문의 각주에 정정본 번호를 덧붙인다 | 근거가 틀렸던 조문을 모르고 지키지 않게 |
| 대기 줄의 후보에 두 번째 근거가 생기면 그날 조문으로 올리고 개정 이력에 적는다 | 승격 규칙을 표준 자신에게도 적용한다 |
이 표준의 전제: 연습 DB 26ai Free 23.26.2 · cpu_count 2 · 한빛유통 데이터 규모(주문 100만 · 고객 2,000) · 18주의 리포트 | 표준도 그때의 규모에서 나왔다. 전제가 바뀌면 다시 센다(마지막 조항을 표준 자신에게도 적용한다) |
마지막 조항 (고정)
모든 성능 결정에 그 당시의 데이터 규모와 근거 수치를 함께 적는다.
강도현이 하지 않은 단 한 가지가 이것이다. 그는 이유를 남겼다(커밋 로그). 숫자도 남겼다(2018-11-06 회의록 본문 "3초 → 0.4초"). 규모도 남겼다(그 회의록 첨부의 맨 끝 줄 "※ 측정 조건 : 운영 DB 복제본, 주문 20,000 건"). 그가 하지 않은 것은 그 셋을 함께, 다음 사람이 보는 자리에 적는 것이었다. 소스에는 "-- 건드리지 말 것 (2018.11 강도현)" 한 줄뿐이었고, 언제 다시 잴지는 어디에도 없었다.
합격증의 '합격'은 정격하중, 정원, 유효기간과 함께 한 장에 적혀 사람이 타는 문 옆에 걸려 있을 때만 의미가 있다(18화 1층 엘리베이터 홀).
| 근거 리포트 | 성능고도화 | 공식문서 |
|---|---|---|
| T2-001 (04화 · "RANGE SCAN으로 변경 완료": 측정 수치가 한 줄도 없는 바인더) · T1 4호 + 대장 1호 (06화 · 회의록 본문에 2만 건이 없었다) · T1 6호 (08화 · 평가 다건 허용 때 '1 쪽'이라는 전제가 깨졌다) · T1 7호 (09화 · 총건수 요구의 이유가 떠났다) · T1 8호 (10화 · "적재 직후 통계 수집"에서 '언제'를 아무도 읽지 않았다) · T4 1호 (12화 · "매기는 곳이 하나뿐"이라는 전제) · T1 11호 (15b화 · "DETERMINISTIC"을 재지 않고 믿었다) · T1 12호 (18화 · "3배 빨라졌습니다": 수치 없는 초안) | 좌표 미확인 | tgdba Performance Improvement Methods (01화) · tgsql Influencing the Optimizer (06화: 힌트는 그 시점의 데이터에 대한 판단) |
개정 이력
| 판 | 화 | 무엇이 바뀌었나 |
|---|---|---|
| v1.0 | 18화 | 제정. 조문 16(근거 2회 이상만) · 대기 줄 9 · 코드 리뷰 체크리스트 26문 · 팩 라이선스 확인란 · 문서 운용 4 · 마지막 조항. SQL 코딩 가이드 v1.0과 함께 냈다(가이드는 SQL을 쓰는 사람의 문서, 이 표준은 튜너와 리뷰어의 문서) |
자매 문서: T0 측정규약 · T9 선정 기준 · SQL 코딩 가이드 v1.0 · 정합성 회귀 체크리스트 · 진단 도구 4열 대응표 · W01 베이스라인 원장 · 리비전 대장