Skip to content

05화 · 블록이라는 그릇 ​

🗓️ 4월 1일 (월) · 02화에서 3주 뒤 · 무대 ora-hanorder오늘 배울 것: DELETE는 행을 지울 뿐 고수위선을 내리지 않는다.

📌 이 화는 기반화다 ​

조각(Q1~N1)은 고치지 않는다. 대신 다음 화에서 갚을 빚을 만들고 숫자로 기록해 둔다. 여기서 만든 고수위선과 공간 빚의 청구서는 14화 「야간 배치가 아침을 넘긴다」로 간다. 그래서 이 화에는 리비전/ 폴더가 없다.


파일 세 개 ​

파일무엇을 하나시간
읽는다1_사건.md95%를 지웠는데 왜 안 빨라지는지 알아내고, 고수위선을 직접 내린 뒤, 테이블이 왜 그렇게 생겼는지까지 파고드는 하루35분
한다3_실습과_기록.md고수위선 9단계 · ROWID 분해 · 행 이전 재현 · T1 리포트 3호60~90분
찾는다2_파고들기.md4계층 · 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 COMPACT3,602 → 3,602. 모으기만 하고 선은 그대로
4차SHRINK SPACE3,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

☠️ 오늘의 함정 — "고쳤는데 왜 그대로지" ​

같은 함정이 세 번 나온다. 셋 다 "했는데 안 변했다"는 함정이다.

  1. DELETE 475,025행: Buffers 3,602 → 3,602
  2. SHRINK SPACE COMPACT: FULL 블록은 0→179로 늘었는데 Buffers는 3,602 → 3,602
  3. ALTER TABLE MOVE: 행 이전은 76,169 → 0이 됐는데 Buffers는 30,549 → 약 10,400(대조군은 735)

"무엇을 바꿨는가"와 "무엇이 측정되는가"는 다른 질문이다. 셋 다 무언가를 바꾸긴 했지만, 측정되는 숫자를 정하는 요인은 따로 있었다.


실습 준비 ​

bash
docker start ora-hanorder

02화를 마친 상태(T_ORD_BIG 100만 행 + 인덱스 2개)에서 시작한다. 실습 스크립트는 모두 맨 앞에서 자기 실습 테이블을 지우고 시작하므로 몇 번을 돌려도 결과가 같다. 교재 본체 테이블(T_ORD_BIG 등)은 건드리지 않는다.

스크립트무엇소요
실습/00_고수위선.sql9단계 [A]~[I]. 오늘 실습의 본체약 10초
실습/01_ROWID와_4계층.sql4계층 · 익스텐트 · ROWID 분해. 읽기 전용즉시
실습/02_행이전과_행연결.sqlPCTFREE 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하는 패턴과 PCTFREE15화

← 04화 「인덱스를 태웠더니 더 느려졌다」 · 교재 전체 안내 · 다음 → 06화 「100만 번의 왕복」