테마
03화 · 실습과 기록
여기서 하는 일: 지울 수 없는 가공을 만나고, 구제책의 대가를 재고, 빠른데 틀린 코드를 잡아낸다.
1_사건.md를 읽은 것은 "선배가 하는 걸 지켜본 것"이고, 이 문서를 끝내야 직접 해 본 것이 된다. 개념이 막히면2_파고들기.md를 펼친다.시간이 없는 주에는 STEP 0 → 1 → 2 → 5 → 6만 한다(약 50분). STEP 5(정합성 사고)는 건너뛰면 안 된다. 이 화의 핵심이 거기 있다.
STEP 0 — 무대를 켜고 전제를 확인한다 (5분)
오늘은 컨테이너가 둘이다. 대부분은 ora-dist에서 하고, 마지막 STEP 6만 ora-hanorder에서 한다.
bash
docker start ora-dist # 본사 레거시 유통 (pup)
docker start ora-hanorder # 한빛유통 (sqlp) — STEP 6 에서만 쓴다처음 만드는 거라면
00_자료준비/고객사/L3_ora-dist/README.md를 따라 한다.
직전 리비전을 연다 ★ 매주 처음 하는 일
bash
cat ../02화_인덱스는_있는데_안_탄다/리비전/Q1_rev02.sql지난주에 잰 값은 Buffers 91이다. 오늘은 이 리비전을 rev03으로 올린다.
전제 확인
sql
-- ora-dist 에서 (기대: 18 / 0 / 500000)
SELECT COUNT(*) AS 테이블수 FROM user_tables;
SELECT COUNT(*) AS 보조인덱스 FROM user_indexes WHERE uniqueness='NONUNIQUE';
SELECT COUNT(*) AS cf10행수 FROM CF10;
-- 오늘의 전제: 날짜가 정말 문자인가 (기대: VARCHAR2 만 6건)
SELECT table_name, column_name, data_type, data_length
FROM user_tab_columns
WHERE column_name IN ('SLE_DT','ORD_DT','APL_DT','INV_BS_DT','INOUT_DT')
ORDER BY table_name;sql
-- ora-hanorder 에서 (기대: 2 — 02화 종료 상태)
SELECT COUNT(*) FROM user_indexes WHERE table_name='T_ORD_BIG';STEP 1 — 예측을 봉인한다 (5분)
CF10.SLE_DT 는 VARCHAR2(8) 이고 '20220101'~'20231231' 이 들어 있다.
현업 코드는 TO_DATE(SLE_DT,'YYYYMMDD') >= DATE '2023-06-01' ... 이다.
SLE_DT 에 인덱스를 만들 것이다.
Q1. 02화에서처럼 "컬럼 가공을 없애면" 되는가? 어떻게 없앨 것인가?
______________________________________________________________
Q2. SLE_DT BETWEEN '20230601' AND '20230630' —
02화에서 "날짜에 BETWEEN 쓰지 마"라고 배웠다. 여기서도 틀리는가? 예 / 아니오
그 이유는? ___________________________________________________
Q3. SLE_DT = 20230601 (따옴표 없음) 은 어떻게 되는가?
① 에러가 난다 ② 답이 틀린다 ③ 답은 맞는데 느려진다 ④ 아무 문제 없다
Q4. 함수 기반 인덱스를 만들면 Buffers 가 얼마가 될 것 같은가? ______
그걸 채택할 것 같은가? 예 / 아니오 — 왜? ____________________▶ 적고 나서 펼치기
Q1: 대부분 "TO_DATE를 지운다"고 쓴다. 하지만 지울 수 없다. 지우면 문자 컬럼을 DATE와 비교하게 된다. 답은 "반대쪽을 문자로 맞춘다"다. 지우는 게 아니라 타입을 맞추는 것이다.
Q2: 아니오. 02화의 BETWEEN 사고는 "DATE 끝값이 자정으로 잘린다"는 문제였다. SLE_DT에는 시분초가 없다(시각은 SLE_HMS에 따로 있다). 실측해 보면 BETWEEN과 >= AND <의 결과 차이는 0이다. 규칙을 외우기 전에 컬럼을 본다.
Q3: ③. 답은 706건으로 맞는데 Buffers가 5 → 1,406이 된다. filter(TO_NUMBER("SLE_DT")=…)가 붙기 때문이다. 단, 같은 실수를 SLE_NO에 하면 ORA-01722 에러로 터진다(값에 하이픈이 있다).
Q4: 59. 그런데 채택하지 않는다. SQL 교정만으로 62가 나오는데, 그 3블록 차이를 위해 모든 INSERT를 고치거나(가상 컬럼) 포맷 한 글자에 무너질 위험을 떠안을(FBI) 이유가 없다. STEP 4에서 직접 잰다.
STEP 2 — 본체: 문자 날짜 실험 (10분) ★
bash
cd 10_본편_튜너의_1년/03화_날짜가_문자로_박혀_있다/실습
docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1 < 00_문자날짜_실험.sqlpowershell
Set-Location 10_본편_튜너의_1년\03화_날짜가_문자로_박혀_있다\실습
Get-Content 00_문자날짜_실험.sql -Encoding UTF8 | docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1스크립트는 맨 앞에서 보조 인덱스와 가상 컬럼, 뷰를 전부 지우고 시작한다. 그래서 몇 번을 돌려도 결과가 같다.
⚠️ 왜 초기화가 필요한가
뒤쪽 STEP에서 만든 FBI나 가상 컬럼이 남아 있으면
[D]가1,406이 아니라 곧장 59로 나온다. 그러면 "가공하면 인덱스를 못 탄다"는 이 화의 출발 장면이 통째로 사라진다. 02화에서 겪은 것과 같은 함정이다.
확인할 것
| 단계 | 조건 | 기대 계획 | 기대 Buffers | ☐ |
|---|---|---|---|---|
| [A] | 인덱스 없이 문자 BETWEEN | TABLE ACCESS FULL | 4,510 | ☐ |
| [B] | 인덱스 + 같은 조건 | INDEX RANGE SCAN | 62 | ☐ |
| [B2] | >= '20230601' AND < '20230701' | INDEX RANGE SCAN | 62 | ☐ |
| [C] | 숫자 BETWEEN 20230601 AND 20230630 | INDEX FAST FULL SCAN | 1,406 | ☐ |
| [C2] | SLE_DT = 20230601 | INDEX FAST FULL SCAN | 1,406 | ☐ |
| [C3] | SLE_DT = '20230601' | INDEX RANGE SCAN | 5 | ☐ |
| [D] | TO_DATE(SLE_DT,'YYYYMMDD') >= … | INDEX FAST FULL SCAN | 1,406 | ☐ |
| [E] | SUBSTR(SLE_DT,1,6) = '202306' | INDEX FAST FULL SCAN | 1,406 | ☐ |
| [E2] | SLE_DT LIKE '202306%' | INDEX RANGE SCAN | 62 | ☐ |
| [F] | 뷰 V_CF10_D 경유 | INDEX FAST FULL SCAN | 1,406 | ☐ |
| [G1] | 조인 · 가공형 | HASH JOIN | 12,585 | ☐ |
| [G2] | 조인 · 교정형 | HASH JOIN | 8,552 | ☐ |
눈으로 짚을 것
[C] — 내가 쓰지 않은 함수를 찾아라
filter(TO_NUMBER("SLE_DT")=20230601)
☐ TO_NUMBER 는 어디서 왔는가? → 오라클이 컬럼 쪽에 끼워 넣었다
[E2] — LIKE 인데 access 가 붙는다
access("SLE_DT" LIKE '202306%')
☐ 선두가 상수이므로 '여기부터 여기까지'를 지목할 수 있다
[F] — 내가 쓴 조건과 Predicate 에 적힌 조건을 비교하라
내가 쓴 것 : SLE_D >= DATE '2023-06-01'
Predicate : filter(TO_DATE("SLE_DT",'YYYYMMDD')>=...)
☐ 조건이 뷰 안쪽으로 밀려 들어갔다 (Predicate Pushing)
[G1] vs [G2] — 어느 줄이 줄었는지 짚어라
CF10 쪽 : TABLE ACCESS FULL 4,510 -> INDEX RANGE SCAN 62 -> ROWID 478
CF11 쪽 : FULL 8,075 -> FULL 8,074 (그대로)
☐ 답은 양쪽 다 45,935건 / 377,266,500원인가?STEP 1의 예측을 꺼낸다
Q1: "TO_DATE를 지운다"고 썼나? | |
Q2: BETWEEN이 여기서는 맞다는 걸 맞혔나? | |
Q3: = 20230601이 ③이라는 걸 맞혔나? |
STEP 3 — 어느 쪽이 변환되는가 (10분)
bash
docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1 < 01_형변환_방향.sqlpowershell
Get-Content 01_형변환_방향.sql -Encoding UTF8 | docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1채점표: 돌리기 전에 각 줄의 결과를 먼저 적어 보자.
| # | 조건 | 내 예상 | 실측 |
|---|---|---|---|
| ① | SLE_DT = '20230601' | INDEX RANGE SCAN · 5 | |
| ② | SLE_DT = 20230601 | INDEX FAST FULL SCAN · 1,406 · TO_NUMBER | |
| ③ | SLE_NO = 20220101 | ORA-01722 (+ ORA-03302로 문제 값까지) | |
| ④ | SLE_DOW = 7 | TABLE ACCESS FULL · 4,511 · TO_NUMBER |
★ 승급 도구 — 10053
스크립트 [5]가 트레이스를 남긴다. 파일 경로는 화면에 찍힌다.
bash
docker exec -i ora-dist grep -n "WCFPD: Current where clause\|finally:\|Final query after transformations" -A 1 <경로>WCFPD: Current where clause predicates "CF10"."SLE_DT"=20230601 ← 내가 쓴 것
TO_NUMBER("CF10"."SLE_DT")=20230601 ← 오라클이 고친 것
Final query after transformations: ... WHERE TO_NUMBER("CF10"."SLE_DT")=20230601☐ Predicate Information에서 본 내용을 함수가 붙는 순간에 다시 본 것임을 확인했는가? ☐ ALTER SESSION 권한이 없어 막혔다면 이 블록만 건너뛴다. 나머지 결론은 바뀌지 않는다.
읽는 법은
2_파고들기.md §6에 있다.
STEP 4 — 구제책을 재 본다 (15분)
bash
docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1 < 02_구제책과_대가.sqlpowershell
Get-Content 02_구제책과_대가.sql -Encoding UTF8 | docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1이 스크립트는 CF10의 데이터를 바꾸지 않는다. 적재 비용은 복사 테이블에서 재고 나서 지운다. (실측해 보니 CF10에 직접
UPDATE하면ROLLBACK해도 세그먼트가 4,583 → 4,608블록으로 커져서 다음 측정값이 달라졌다.)
되는 것
| 단계 | 무엇 | 기대 | ☐ |
|---|---|---|---|
| [P1] | FBI를 만들고 SQL을 고치지 않은 채 가공 조건으로 | 59 | ☐ |
| [P2] | 같은 FBI로 뷰를 거치는 화면도 | 59 | ☐ |
| [R1] | 가상 컬럼 SLE_D로 | 59 | ☐ |
| [R2] | 가상 컬럼을 만든 뒤 원래 가공 조건(SQL 수정 없음) | 59 | ☐ |
[R2]의 Predicate는 반드시 눈으로 짚어 본다. 내가 쓴 TO_DATE(SLE_DT,'YYYYMMDD')가 access("CF10"."SLE_D">=…)로 치환되어 있다. 옵티마이저가 식을 가상 컬럼으로 바꿔치기한 것이다.
대가
| 단계 | 무엇 | 기대 | ☐ |
|---|---|---|---|
| [Q1] | TRUNC(TO_DATE(…))로 한 번 더 감싸면 | FAST FULL SCAN 1,340 | ☐ |
| [Q2] | 포맷을 'yyyymmdd' 소문자로만 바꾸면 | FAST FULL SCAN 1,406 | ☐ |
| [S1] | 값 9개짜리 기존 INSERT | ORA-00947 | ☐ |
| [S2] | 가상 컬럼에 값을 주면 | ORA-54013 | ☐ |
| [T] | 인덱스 0/1/2개의 redo | 약 3.7 / 9.2~9.5 / 14.5~14.8MB | ☐ |
📌 이 STEP에서 가장 중요한 것은 [Q2]다
'YYYYMMDD'와'yyyymmdd'는 같은 뜻이고 같은 답을 낸다. 그런데 59와 1,406으로 갈린다. 함수 기반 인덱스는 식이 글자 단위로 일치해야 탄다. 운영에서 "FBI를 만들었는데 왜 어떤 화면만 안 타죠?"라는 질문의 절반은 여기서 나온다.
판단 — 채택할 것인가
| 대안 | 내가 잰 값 | 채택? | 이유 |
|---|---|---|---|
| SQL 교정 + 인덱스 1개 | 4,510 → ____ | ||
| FBI | 1,406 → ____ | ||
| 가상 컬럼 | 1,406 → ____ |
채택하지 않기로 했다면 그 이유를 숫자로 적는다. 그게 T1 리포트 6번 칸이다. "재 보지도 않고 '안 씁니다'라고 쓰면 게으른 것이고, 재 보고 안 쓰는 것과는 다르다."
STEP 5 — ☠️ 빠른데 틀린 코드를 잡는다 (15분) ★ 건너뛰면 안 된다
bash
docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1 < 03_시각_패딩_검증.sqlpowershell
Get-Content 03_시각_패딩_검증.sql -Encoding UTF8 | docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1먼저: 왜 SLE_DT는 되는가
| 조건 | SLE_DT | ☐ |
|---|---|---|
| ① 길이가 항상 같다 | 최소 8 = 최대 8 | ☐ |
| ② 앞을 0으로 채운다 | 비숫자 0건 · 전 행 8자리 | ☐ |
| ③ 큰 단위가 왼쪽 | YYYYMMDD | ☐ |
그리고: SLE_HMS는 ②를 어겼다
길이 건수 최소값 최대값
5 33241 80000 95959 ← 8시대 16,622 · 9시대 16,619
6 466759 100000 225959☐ '95959'와 '180000' 중 문자 비교에서 어느 쪽이 큰가? 왼쪽부터 손으로 비교해 보자.
사고 재현
| 건수 | 금액 | ☐ | |
|---|---|---|---|
현업 쿼리 SLE_HMS BETWEEN '090000' AND '180000' | 841,623 | 6,920,497,000 | ☐ |
제대로 TO_NUMBER(SLE_HMS) BETWEEN 90000 AND 180000 | 877,913 | 7,217,788,000 | ☐ |
| 차이 | 36,290 | 297,291,000 | ☐ |
☠️☠️ 그리고 여기가 핵심
| 계획 | Buffers | 결과 | ☐ | |
|---|---|---|---|---|
| 원본 | INDEX RANGE SCAN · access | 966 | 383,578 (틀림) | ☐ |
교정형 LPAD(…) | INDEX FAST FULL SCAN · filter | 1,264 | 400,197 (맞음) | ☐ |
스스로에게 물어본다
"내가 오늘 이 쿼리를 '튜닝 대상'으로만 봤다면, 966을 그냥 통과시켰을까?" 그리고 "누가
LPAD로 고쳐 왔다면 나는 '느려졌다'고 반려했을까?"02화: "느린 코드를 빠르게 만드는 것이 튜닝이고, 맞는 코드를 틀리게 만드는 것은 장애다." 02화에서는 내가 그런 코드를 쓰려다 걸렸고, 03화에서는 이미 운영에서 돌고 있는 코드가 그렇다.
포맷 혼입 · 교정의 세 갈래 · 회귀 검증
☐ [Z]: '2023-06-01'이 섞이면 범위에서 조용히 빠지는 것을 확인했는가? ☐ [AA]: 데이터 교정 비용(33,241건 · redo 약 8.9MB)과 CHECK 제약을 확인했는가? ☐ [BB]: 회귀 검증 세 줄이 전부 0인가? (0이 아니면 STEP 2의 교정이 답을 바꾼 것이다)
STEP 6 — Q1을 rev03으로 (10분) ★ 컨테이너가 바뀐다
bash
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 04_한빛유통_rev03.sqlpowershell
Get-Content 04_한빛유통_rev03.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1오늘 pup에서 배운 규칙을 방향을 뒤집어 적용한다.
| 단계 | 조건 | 기대 | ☐ |
|---|---|---|---|
| [1] | rev02 (리터럴) | INDEX RANGE SCAN · 91 | ☐ |
| [3] | 바인드 + TO_CHAR(ORD_DT,'YYYYMM') = :p_ym | TABLE ACCESS FULL · 5,826 | ☐ |
| [4] | rev03: 경계를 리터럴 쪽에서 계산 | FILTER + RANGE SCAN · 91 | ☐ |
| [5] | ORD_DT >= '01-JUN-24' (NLS DD-MON-RR) | 91 · 컬럼은 맨몸 | ☐ |
| [6a] | ORD_DT >= '2024-06-01' (NLS DD-MON-RR) | ORA-01861 | ☐ |
| [6c] | ORD_DT >= '01-JUN-24' (NLS YYYY-MM-DD) | ☠️ 1,000,000행 · 에러 없음 | ☐ |
| [7] | 회귀 검증 | 건수차 0 · 금액차 0 | ☐ |
☠️ [6c]는 반드시 직접 본다
TO_DATE('01-JUN-24')가0001-06-24날짜로 해석된다. 세션 설정 하나로 같은 코드가 27,390건에서 1,000,000건으로 바뀌고, 에러는 나지 않는다.ORA-01861은 차라리 친절한 편이다.날짜를 변환할 때는 항상 포맷을 명시한다.
TO_DATE(x,'YYYYMMDD')처럼 쓴다.
[3]과 [4]의 차이를 한 문장으로 써 보자. 둘 다 바인드가 문자이고 컬럼이 DATE다. 무엇이 달랐나?
______________________________________________________________리비전은 리비전/Q1_rev03.sql에 남는다.
STEP 7 — T1 리포트 2호 ★ 오늘의 산출물
양식은 T1_단건SQL_튜닝리포트.md를 따른다. 오늘은 리포트를 두 개 쓴다. 하나는 성능, 하나는 정합성이다.
┌──────────────────────────────────────────────────────────────────┐
│ T1 단건 SQL 튜닝 리포트 — 2호 │
├──────────────────────────────────────────────────────────────────┤
│ 1. 대상 : 본사 레거시 유통 · 월 매출 조회 (CF10 x CF11) │
│ + PKG_ORD_STLM.Q1 rev02 -> rev03 │
│ 2. 측정 환경 : ora-dist / ora-hanorder · 26ai Free 23.26.2.0.0 │
│ CF10 500,000행 · 통계 수집 시각 ______ │
│ 3. 부하 조건 : 단독 세션 · 1회 실행 │
│ 4. 현상 : ______________________________________________ │
│ 5. 원인 : ______________________________________________ │
│ [성능고도화 II권 Ch1 04절] [sqlrf Data Type …] │
│ 6. 개선안 : 채택 ________________________________________ │
│ ★ 채택하지 않은 대안과 그 이유 (오늘 처음 쓴다) │
│ FBI : 잰 값 ______ / 안 쓴 이유 ________________ │
│ 가상 컬럼 : 잰 값 ______ / 안 쓴 이유 ________________ │
│ 7. 효과 : Buffers ______ -> ______ │
│ Q1: 91 -> 91 (개선이 아니라 '유지') │
│ 8. 정합성 회귀 : ____________________________________________ │
│ 9. 환경 의존성 : ____________________________________________ │
│10. 리스크 : ★ 비우면 반려된다 _____________________________ │
│11. 롤백 절차 : ____________________________________________ │
│12. 재측정 계획: ____________________________________________ │
└──────────────────────────────────────────────────────────────────┘6번 「채택하지 않은 대안」 — 오늘 새로 생긴 칸
02화 리포트에서는 이 칸이 비어 있었다. 오늘은 잰 값이 있다.
- FBI:
1,406 → 59. 안 쓴다. 포맷 문자열의 대소문자 하나로 1,406으로 돌아간다(실측) - 가상 컬럼:
1,406 → 59. 안 쓴다. 모든INSERT를 고쳐야 하고(ORA-00947/ORA-54013) redo가 약 4배로 는다 - 컬럼 타입을
DATE로 변경: 안 한다. 참조 코드 범위를 확인하지 못했고,SLE_NO에 날짜가 들어 있다. 별건 과제로 제안한다
9번 「환경 의존성」 — 오늘은 쓸 거리가 분명하다
Q1의 날짜 리터럴은 세션NLS_DATE_FORMAT에 의존하면 안 된다. 실측해 보면 같은 코드가 27,390 ↔ 1,000,000을 오간다- 배치 서버와 개발 PC의
NLS설정을 대조한다
10번 「리스크」
CF10의 인덱스가 0개 → 1개로 늘었다. 적재 redo가 약 2.5배가 된다(실측 약 3.7MB → 약 9.3MB / 50,000건). 14화에서 다룬다- 운영에 적용할 때는
INVISIBLE로 먼저 만든다(02화 수칙) - 오늘 잰 범위는 2023년 6월 한 달(4.19%)이다. 범위가 넓어지면 판단이 바뀔 수 있다(04화)
★ 별도: 정합성 사고 보고 (T4 전신)
성능 리포트와 분리해서 쓴다. 이건 튜닝 결과가 아니라 장애 보고다.
┌──────────────────────────────────────────────────────────────────┐
│ 정합성 이상 보고 — SLE_HMS 영업시간 집계 │
├──────────────────────────────────────────────────────────────────┤
│ 현상 : 영업시간(09:00~18:00) 매출이 회계 대비 297,291,000원 부족 │
│ 범위 : 36,290건 (CF10 기준 16,619건) · 2022-01-01 ~ 2023-12-31 │
│ 원인 : ______________________________________________________ │
│ 즉시 조치(증상) : ______________________________________________ │
│ 근본 조치(원인) : ______________________________________________ │
│ 비용: 33,241건 UPDATE · redo 약 8.9MB · 승인 필요 │
│ 재발 방지 : ___________________________________________________ │
│ ★ 주의 : 증상 조치(LPAD)는 Buffers 966 -> 1,264 로 '느려진다'. │
│ 느려진 쪽이 맞는 답이다. 성능 지표만으로 반려하지 말 것. │
└──────────────────────────────────────────────────────────────────┘STEP 8 — 서술 답안 (400~600자)
유통지원팀에 보낼 회신을 쓴다. 느린 것과 틀린 것, 두 가지를 모두 담아야 한다.
4단계 프레임(현상/진단 → 원인 → 개선안 → 근거/효과)은 01화 3_실습과_기록.md와 같다.
▶ 선배의 첨삭 포인트 (쓰고 나서)
① 순서를 바꾼다. 그쪽이 먼저 물은 건 "느리다"지만, 먼저 보고해야 할 것은 2억 9,729만 원이다. 돈이 틀린 건은 성능보다 앞선다.
② "데이터가 잘못됐습니다"로 끝내지 않는다. 그 데이터를 만든 건 그쪽 시스템이고, 10년 동안 그렇게 돌았다. 언제부터, 몇 건, 얼마인지를 숫자로 주고, 교정 비용(33,241건 · 약 8.9MB)과 재발 방지책까지 함께 준다. 결정은 그쪽이 한다.
③ 성능은 조건을 붙여서 쓴다. "72배 빨라졌습니다"가 아니라 "2023년 6월 한 달(전체의 4.19%) 조회에서 읽는 블록이 4,510에서 62로 줄었습니다"라고 쓴다. 범위가 커지면 이 숫자는 나오지 않는다.
④ 하지 않은 것을 쓴다. 컬럼 타입 변경을 검토했지만 하지 않았다는 사실과 그 이유를 쓴다. 쓰지 않으면 다음 사람이 또 검토하게 된다.
⑤ 남은 것을 쓴다. 조인 쪽 CF11 FULL 8,075는 그대로다. 숨기지 말고 "다음 과제"로 올린다.
STEP 9 — 파인만 자가설명
절차는 01화와 같다. 1단 백지 설명 → 2단 막힘 태그(최소 1개) → 3단 원천 복귀 → 4단 재설명 순서로 진행한다.
오늘 자주 나오는 태그 세 가지
| 태그 | 전형적인 문장 | 복귀처 |
|---|---|---|
#인과 | "왜 SLE_DT = 20230601에서 컬럼 쪽이 변환되는지 설명하다가 막혔다" | §1 |
#경계 | "02화에서는 BETWEEN이 틀렸는데 여기서는 맞는 이유를 말로 못 하겠다" | §7 |
#판단 | "59가 62보다 좋은데 왜 안 쓰는지 설명이 안 된다" | §4.5 |
4단 되묻기 3문 (오늘 버전)
- 조건 반전: "
SLE_DT가VARCHAR2(10)에'2023-06-01'형식이었다면 오늘 결론이 어떻게 달라지나?" - 반례 요구: "
TO_NUMBER가 붙었는데도 성능이 문제가 안 되는 경우를 하나 든다면?" - 측정 지목: "'이 시스템의 다른 문자 날짜 컬럼도 같은 문제가 있다'를 증명하려면 무엇을 재야 하나?" (힌트: 이 스키마에는 문자 날짜 컬럼이 6개 있다)
태그는 _막힘로그.md로 옮긴다.
완료 체크리스트
- [ ] STEP 0:
Q1_rev02.sql을 열어 봤고,SLE_DT가VARCHAR2(8)인 것을 직접 확인했다 - [ ] STEP 1: 보기 전에 예측 4개를 적었다
- [ ] STEP 2:
[A]~[G2]를 돌리고 4,510 → 62를 확인했다 - [ ] STEP 2:
[F]에서 조건이 뷰 안으로 밀려 들어간 것을 눈으로 짚었다 - [ ] STEP 3:
TO_NUMBER가 내가 쓰지 않은 함수임을 확인했고,ORA-01722를 직접 봤다 - [ ] STEP 4:
[Q2]에서 대소문자 하나로 59 → 1,406이 되는 것을 봤다 - [ ] STEP 4: FBI와 가상 컬럼을 재 보고 채택하지 않기로 했고, 그 이유를 숫자로 적었다
- [ ] STEP 5: 원본 966(틀림)과 교정형 1,264(맞음)를 직접 비교했다
- [ ] STEP 5: 회귀 검증 세 줄이 전부 0인 것을 확인했다
- [ ] STEP 6:
[6c]에서 1,000,000행이 에러 없이 돌아오는 것을 봤다 - [ ] STEP 7: T1 2호의 6번(채택하지 않은 대안), 9번(환경 의존성), 10번(리스크)을 채웠다
- [ ] STEP 7: 정합성 사고 보고를 별도로 썼다
- [ ] STEP 9: 막힘 태그를 최소 1개
_막힘로그.md에 옮겼다
완결성 게이트: STEP 4의 「채택하지 않은 대안」, STEP 5의 966 vs 1,264, STEP 9의 태그. 셋 중 하나라도 비어 있으면 이 화는 미완성이다.
다음 화로 넘기는 상태
| 무엇 | 값 |
|---|---|
CF10 인덱스 | 1개 (IX_CF10_SLE_DT). 지우지 않는다 · 컬럼 9개 · 데이터·블록 수 변경 없음(4,583) |
ora-dist에 남는 객체 | 인덱스 IX_CF10_SLE_DT · 뷰 V_CF10_D. 임시 테이블은 스크립트가 지운다 |
T_ORD_BIG 인덱스 | 2개 (02화 그대로) |
Q1 현재 리비전 | rev03 · Buffers 91 (바인드 형태) |
| 남긴 빚 | CF11 FULL 8,075 → 06화 · 인덱스 redo → 14화 |
| 열어 둔 질문 | CF10의 CF 9,921 vs T_ORD_BIG의 CF 1,000,000 → 04화 |
| 승인 대기 | SLE_HMS 데이터 교정 (33,241건) → 09화 |
다음 → 04화 「인덱스를 태웠더니 더 느려졌다」: 02화에서 미뤄 둔 CF 1,000,000과 손익분기점을 다룬다. 오늘 CF10에서 본 CF 9,921이 그 비교 대상이 된다.