Skip to content

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_문자날짜_실험.sql
powershell
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]인덱스 없이 문자 BETWEENTABLE ACCESS FULL4,510☐
[B]인덱스 + 같은 조건INDEX RANGE SCAN62☐
[B2]>= '20230601' AND < '20230701'INDEX RANGE SCAN62☐
[C]숫자 BETWEEN 20230601 AND 20230630INDEX FAST FULL SCAN1,406☐
[C2]SLE_DT = 20230601INDEX FAST FULL SCAN1,406☐
[C3]SLE_DT = '20230601'INDEX RANGE SCAN5☐
[D]TO_DATE(SLE_DT,'YYYYMMDD') >= …INDEX FAST FULL SCAN1,406☐
[E]SUBSTR(SLE_DT,1,6) = '202306'INDEX FAST FULL SCAN1,406☐
[E2]SLE_DT LIKE '202306%'INDEX RANGE SCAN62☐
[F]뷰 V_CF10_D 경유INDEX FAST FULL SCAN1,406☐
[G1]조인 · 가공형HASH JOIN12,585☐
[G2]조인 · 교정형HASH JOIN8,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_형변환_방향.sql
powershell
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 = 20230601INDEX FAST FULL SCAN · 1,406 · TO_NUMBER
③SLE_NO = 20220101ORA-01722 (+ ORA-03302로 문제 값까지)
④SLE_DOW = 7TABLE 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_구제책과_대가.sql
powershell
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개짜리 기존 INSERTORA-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 → ____
FBI1,406 → ____
가상 컬럼1,406 → ____

채택하지 않기로 했다면 그 이유를 숫자로 적는다. 그게 T1 리포트 6번 칸이다. "재 보지도 않고 '안 씁니다'라고 쓰면 게으른 것이고, 재 보고 안 쓰는 것과는 다르다."


STEP 5 — ☠️ 빠른데 틀린 코드를 잡는다 (15분) ★ 건너뛰면 안 된다 ​

bash
docker exec -i ora-dist sqlplus -s pup/pup@localhost/FREEPDB1 < 03_시각_패딩_검증.sql
powershell
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,6236,920,497,000☐
제대로 TO_NUMBER(SLE_HMS) BETWEEN 90000 AND 180000877,9137,217,788,000☐
차이36,290297,291,000☐

☠️☠️ 그리고 여기가 핵심 ​

계획Buffers결과☐
원본INDEX RANGE SCAN · access966383,578 (틀림)☐
교정형 LPAD(…)INDEX FAST FULL SCAN · filter1,264400,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.sql
powershell
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_ymTABLE 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문 (오늘 버전) ​

  1. 조건 반전: "SLE_DT가 VARCHAR2(10)에 '2023-06-01' 형식이었다면 오늘 결론이 어떻게 달라지나?"
  2. 반례 요구: "TO_NUMBER가 붙었는데도 성능이 문제가 안 되는 경우를 하나 든다면?"
  3. 측정 지목: "'이 시스템의 다른 문자 날짜 컬럼도 같은 문제가 있다'를 증명하려면 무엇을 재야 하나?" (힌트: 이 스키마에는 문자 날짜 컬럼이 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이 그 비교 대상이 된다.