테마
05화 · 블록이라는 그릇
🗓️ 4월 1일 (월) · 02화에서 3주 뒤 · 무대
ora-hanorder오늘 배울 것:DELETE는 행을 지울 뿐 고수위선을 내리지 않는다.
📌 이 화는 기반화다
조각(Q1~N1)은 고치지 않는다. 대신 다음 화에서 갚을 빚을 만들고 숫자로 기록해 둔다. 여기서 만든 고수위선과 공간 빚의 청구서는 14화 「야간 배치가 아침을 넘긴다」로 간다. 그래서 이 화에는
리비전/폴더가 없다.
파일 세 개
| 파일 | 무엇을 하나 | 시간 | |
|---|---|---|---|
| 읽는다 | 1_사건.md | 95%를 지웠는데 왜 안 빨라지는지 알아내고, 고수위선을 직접 내린 뒤, 테이블이 왜 그렇게 생겼는지까지 파고드는 하루 | 35분 |
| 한다 | 3_실습과_기록.md | 고수위선 9단계 · ROWID 분해 · 행 이전 재현 · T1 리포트 3호 | 60~90분 |
| 찾는다 | 2_파고들기.md | 4계층 · HWM · 회수 4종 · 블록 내부(ITL·행 디렉터리·PCTFREE) · 이전 vs 연결 · ROWID | 필요할 때 |
1을 읽고 3을 따라 한다. 2는 막힐 때 펼친다. 시간이 없는 주에는 1_사건을 중단 지점 1까지 읽고 3_실습은 STEP 0, 1, 2, 6만 한다(약 40분).
지난 화에서 들고 오는 것
Q1 커버링 인덱스 | 02화에서 5,827 → 91 |
T_ORD_BIG 인덱스 | 2개 (IX_ORD_BIG_DT, IX_ORD_BIG_DT_AMT). 오늘 처음으로 이 둘의 크기를 잰다 |
| 01화가 남긴 약속 | "이 캐리어 기억해 둬. 캐리어 하나에 몇 잔이 들어 있느냐보다 더 고약한 문제가 있거든." |
오늘이 바로 그 "더 고약한 문제"를 보는 날이다.
그리고 전화가 한 통 걸려 왔다.
"지난주에 이력 데이터 정리했다면서요. 2년 11개월치 지웠다고. 그런데 조회가 똑같아요." (정산 현업 조민우)
오늘의 전개 — 네 번 틀리고 한 번 내린다
| 한 일 | 결과 | |
|---|---|---|
| 1차 | "통계를 다시 안 모았겠지" | NUM_ROWS 24,975. 통계는 멀쩡했다 |
| 2차 | "블록 안이 비었으면 적게 읽겠지" | FULL 0 · FS4 3,123. 비어도 읽는다 |
| 3차 | SHRINK SPACE COMPACT | 3,602 → 3,602. 모으기만 하고 선은 그대로 |
| 4차 | SHRINK SPACE | 3,602 → 183 |
| 덤으로 한 번 더 틀림 | "VARCHAR2(4000)이 공간을 먹겠지" | 874 = 874. 한 블록도 차이 없다 |
왜 네 번이나 틀리게 짰을까? "데이터를 지우면 빨라진다"는 믿음은 가장 끈질기게 살아남는 믿음이기 때문이다. 이 믿음은 SQL을 아무리 잘 써도 깨지지 않는다. 저장 구조를 봐야 깨진다.
오늘 배우는 한 문장
전체 스캔이 읽는 범위는 "행이 어디까지 있나"가 아니라 "어디까지 써 봤나"로 정해진다.
그 "어디까지 써 봤나"를 표시한 선이 고수위선(High Water Mark)이고, DELETE는 이 선을 내리지 않는다.
🔑 오늘의 비유 — 3층 문서보관실의 분필 선
선반에는 상자를 왼쪽부터 빈칸 없이 채운다. 총무팀은 상자가 가장 오른쪽까지 간 자리에 분필로 선을 긋는다. 실사할 때는 분필 선까지 상자를 하나하나 열어 본다. 비었는지는 열어 봐야 알기 때문이다.
작년에 상자 안의 서류만 싹 버리고, 상자도 분필 선도 그대로 뒀다. 그래서 실사 시간도 그대로였다.
| 보관실 | 오라클 |
|---|---|
| 선반 칸 하나 | 블록 (8KB. 01화의 커피 캐리어) |
| 한 번에 새로 받는 선반 한 줄 | 익스텐트 |
| 우리 팀 구역 | 세그먼트 |
| 분필 선 | 고수위선 (HWM) |
| 서류만 버리기 | DELETE |
| 상자를 왼쪽으로 모으기 | SHRINK SPACE COMPACT |
| 모으고 분필 선 다시 긋기 | SHRINK SPACE |
| 구역을 통째로 비우기 | TRUNCATE |
| "B-47 칸으로 옮겼음" 쪽지 | 행 이전 (fb: --H----- + nrid) |
| 칸에 여유를 남겨 두는 규칙 | PCTFREE |
☠️ 오늘의 함정 — "고쳤는데 왜 그대로지"
같은 함정이 세 번 나온다. 셋 다 "했는데 안 변했다"는 함정이다.
DELETE475,025행:Buffers3,602 → 3,602SHRINK SPACE COMPACT:FULL블록은 0→179로 늘었는데Buffers는 3,602 → 3,602ALTER TABLE MOVE: 행 이전은 76,169 → 0이 됐는데Buffers는 30,549 → 약 10,400(대조군은 735)
"무엇을 바꿨는가"와 "무엇이 측정되는가"는 다른 질문이다. 셋 다 무언가를 바꾸긴 했지만, 측정되는 숫자를 정하는 요인은 따로 있었다.
실습 준비
bash
docker start ora-hanorder02화를 마친 상태(T_ORD_BIG 100만 행 + 인덱스 2개)에서 시작한다. 실습 스크립트는 모두 맨 앞에서 자기 실습 테이블을 지우고 시작하므로 몇 번을 돌려도 결과가 같다. 교재 본체 테이블(T_ORD_BIG 등)은 건드리지 않는다.
| 스크립트 | 무엇 | 소요 |
|---|---|---|
실습/00_고수위선.sql | 9단계 [A]~[I]. 오늘 실습의 본체 | 약 10초 |
실습/01_ROWID와_4계층.sql | 4계층 · 익스텐트 · ROWID 분해. 읽기 전용 | 즉시 |
실습/02_행이전과_행연결.sql | PCTFREE 5종 · 행 이전 · 행 연결 · MOVE 함정 | 약 1분 |
실습/03_VARCHAR2_4000.sql | 선언 길이가 쓰는 것과 안 쓰는 것 | 약 10초 |
실습/90_블록덤프_SYSDBA.sql | 선택. 블록 안의 ITL·행 디렉터리·nrid를 눈으로 확인 | 약 5초 |
SYSDBA 권한은
90_에만 필요하다. Git Bash에서는MSYS_NO_PATHCONV=1을 꼭 붙여야 한다.
이 화의 산출물
| 무엇 | 어디 |
|---|---|
T1 단건 SQL 튜닝 리포트 3호 ★ (SQL은 그대로 두고 저장 구조와 보관 정책을 고친 첫 리포트. Buffers 3,602 → 3,602의 이유) | 3_실습 STEP 6 · T1 양식 |
리비전/ | 없다. 이 화는 SQL을 고치지 않는다 |
이 화가 다음으로 넘기는 것
| 무엇 | 어디로 |
|---|---|
보관을 DELETE로만 하는 정책의 비용 (3,602 → 3,602 → 183, 매달 반복) | 14화: 청구서가 날아온다 |
인덱스 2개 48MB (T_ORD_BIG 테이블 47MB보다 크다) | 14화: 02화에서 미뤄 둔 적재 비용 |
MOVE로도 돌아오지 않는 클러스터링 팩터 (약 52,200 vs 3,449) | 04화의 CF와 같은 원리. 고치는 법은 04화에서 이미 봤다 |
| ITL 슬롯이 모자라면 어떻게 되는가 | 12화 · 13화 |
배치가 상태 컬럼을 UPDATE하는 패턴과 PCTFREE | 15화 |
← 04화 「인덱스를 태웠더니 더 느려졌다」 · 교재 전체 안내 · 다음 → 06화 「100만 번의 왕복」