Skip to content

05화 · 실습과 기록 ​

여기서 하는 일: 95%를 지우고, 안 줄어드는 걸 확인한 뒤, 고수위선을 직접 내린다.1_사건.md를 읽은 것은 "선배가 하는 걸 지켜본 것"이고, 이 문서를 끝내야 직접 해 본 것이 된다. 개념이 막히면 2_파고들기.md를 펼친다.

시간이 없는 주에는 STEP 0 → 1 → 2 → 6만 한다(약 40분).


STEP 0 — 기반화에서 처음 하는 일 (3분) ​

조각 개선화는 직전 리비전의 diff를 뜨는 일로 시작한다. 05화는 기반화라서 고칠 조각이 없다. 대신 아래 내용을 먼저 적는다.

이 화가 다음에 청구서를 보낼 화 : 14화 「야간 배치가 아침을 넘긴다」
보낼 것 :
  ① 보관을 DELETE 로만 하는 정책이 만드는 고수위선 빚
  ② 매달 반복되는 SHRINK/MOVE 의 비용
  ③ 02화에서 만든 인덱스 2개(48MB)의 적재 비용
bash
docker start ora-hanorder
sql
-- 전제 확인 (02화 종료 상태)
SELECT table_name, num_rows, blocks FROM user_tables WHERE table_name='T_ORD_BIG';
--   기대: 1,000,000 / 5,923
SELECT index_name FROM user_indexes WHERE table_name='T_ORD_BIG';
--   기대: IX_ORD_BIG_DT, IX_ORD_BIG_DT_AMT

blocks가 5,923이 아니면 통계를 다시 수집한다. EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'T_ORD_BIG',method_opt=>'FOR ALL COLUMNS SIZE 1',cascade=>TRUE,no_invalidate=>FALSE);


STEP 1 — 예측을 봉인한다 (3분) ​

50만 행짜리 로그 테이블이 있다. 전체 스캔 Buffers 는 3,602 다.
여기서 95%(475,025행)를 DELETE 하고 통계를 다시 모을 것이다.

Q1. DELETE 후 같은 조회의 Buffers 는 얼마가 될 것 같은가?       ______
Q2. 틀렸다면, 왜 그렇게 되는가?
    ________________________________________________________
Q3. VARCHAR2(4000) 컬럼 3개짜리 테이블과, 같은 값을 담은
    VARCHAR2(2)/(30)/(100) 테이블의 블록 수 비는?     ______ : ______
Q4. 행을 72바이트로 넣고 나중에 270바이트로 UPDATE 하면,
    전체 스캔은 몇 배 느려질 것 같은가?   ______
    인덱스 경유는?                        ______
▶ 적고 나서 펼치기
  • Q1: 대부분 "20분의 1"이나 "크게 준다"라고 쓴다. 실측값은 3,602. 한 블록도 줄지 않는다.
  • Q3: 대부분 "4000 쪽이 훨씬 크다"라고 쓴다. 실측값은 874 : 874로 똑같다.
  • Q4: 전체 스캔은 1.13배(3,904 vs 3,469)밖에 늘지 않는다. 인덱스 경유는 41.6배(30,549 vs 735)로 터진다.

이 화는 네 번 틀리도록 짜여 있다. 01화나 02화와 달리 오늘은 "고치는" 화가 아니라 "왜 이렇게 됐는지 알아내는" 화다.


STEP 2 — 고수위선 사건 (10분) ★ 오늘의 본체 ​

bash
cd 10_본편_튜너의_1년/05화_블록이라는_그릇/실습
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 00_고수위선.sql
powershell
Set-Location 10_본편_튜너의_1년\05화_블록이라는_그릇\실습
Get-Content 00_고수위선.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1

스크립트는 맨 앞에서 실습 테이블을 지우고 시작한다. 그래서 몇 번을 돌려도 결과가 같다.

⚠️ 왜 초기화가 필요한가 — 실측으로 걸린 함정 ​

[G]에서 SHRINK SPACE를 한 뒤 스크립트를 다시 돌리면 [B]가 3,602가 아니라 183에서 시작한다. "지웠는데 안 줄어든다"는 이 화의 핵심 장면이 통째로 사라진다. 고수위선이 올라간 상태에서 출발해야 이 이야기가 성립한다.

아홉 단계에서 확인할 것 ​

단계무엇기대☐
[A]50만 행 적재세그먼트 3,712블록 · 익스텐트 44 · HWM 아래 3,665☐
[B]전체 스캔TABLE ACCESS FULL · 3,602 · A-Rows 100,000☐
[C]95% DELETE남은 행 24,975 · 세그먼트·익스텐트·HWM 전부 그대로☐
[D]★ 같은 전체 스캔3,602. A-Rows만 4,995로 줄었다☐
[E]SPACE_USAGEFULL 0 · FS4 3,123☐
[F]SHRINK SPACE COMPACTFULL 0→179로 모였는데 여전히 3,602☐
[G]SHRINK SPACEHWM 180 · 익스텐트 44→17 · 183☐
[H]ALTER TABLE MOVEHWM 192 · 183☐
[I]TRUNCATE세그먼트 8블록 · 익스텐트 1 · 1☐

각 단계에서 눈으로 짚을 것 ​

[C][D] — 세 숫자를 나란히 보라
    USER_SEGMENTS.blocks  3712 -> 3712   받아 놓은 공간: 그대로
    USER_TABLES.blocks    3665 -> 3665   고수위선:       그대로
    Buffers               3602 -> 3602   읽는 양:        그대로
    NUM_ROWS            500000 -> 24975  행만 줄었다
    ☐ "읽는 양은 행수가 아니라 고수위선이 정한다" 를 이 네 줄로 말할 수 있는가?

[E] — FULL 이 0 이라는 것
    ☐ 3,123개 블록이 75% 이상 비었는데도 왜 전부 읽히는가?
      -> 블록을 열어 봐야 비었는지 안다. 안 열면 모른다

[F] — 모으는 것과 선을 내리는 것은 다른 일이다
    FULL  0 -> 179    (행이 앞쪽 179 블록에 모였다)
    blocks 3665 -> 3665 (선은 그대로)
    Buffers 3602 -> 3602
    ☐ 왜 이 둘을 분리해 놨는지 설명할 수 있는가? (힌트: 잠금 시간)

[G] — 익스텐트까지 반납된다
    ☐ 44 -> 17 로 줄어든 것을 확인. SHRINK 는 공간도 돌려준다

STEP 1의 예측을 꺼낸다 ​

Q1을 맞혔나?
"COMPACT로는 안 내려간다"를 예상했나?
TRUNCATE가 1블록이 되는 것을 예상했나?

STEP 3 — 주소를 분해한다 (10분) ​

bash
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 01_ROWID와_4계층.sql
powershell
Get-Content 01_ROWID와_4계층.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1

읽기 전용 스크립트다. 아무것도 바꾸지 않는다.

채점표 — 돌리기 전에 먼저 답해 보자 ​

#질문내 답실측
①T_ORD_BIG 세그먼트가 받은 블록은?6,016
②고수위선 아래 블록은?5,923
③전체 스캔이 읽는 블록은?5,826
④행이 실제로 들어 있는 블록은?5,813
⑤익스텐트 62개는 전부 같은 크기인가?아니다. 64KB 16개 + 1MB 46개
⑥ROWID 네 조각 중 테이블스페이스는 몇 번째?없다
⑦상대 파일번호 1024를 쓰는 테이블스페이스는 몇 개?3개 (SYSTEM·SYSAUX·UNDOTBS1)
⑧01화의 "블록당 169건"을 ROWID로 다시 세면?172

📌 ④와 ②의 차이를 꼭 설명하고 넘어가자 ​

5,923 − 5,813 = 110. 고수위선 아래인데 행이 하나도 없는 블록이 110개다. 저 110개는 매번 읽힌다. T_ORD_BIG에도 이미 작은 빚이 있다.

⑦이 왜 결정적인가 ​

sql
-- 이 함수의 인자 개수를 보라
DBMS_ROWID.ROWID_TO_ABSOLUTE_FNO(row_id, schema_name, object_name)

ROWID만으로 절대 파일 번호를 구할 수 있었다면 인자가 하나면 됐다. 오라클이 만든 API가 소유자와 객체명을 요구하는 것 자체가 "그 정보는 ROWID 안에 없다"는 증거다.


STEP 4 — 행 이전을 만든다 (15분) ​

bash
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 02_행이전과_행연결.sql
powershell
Get-Content 02_행이전과_행연결.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1

⚠️ UPDATE가 네 번 들어 있어 약 1분 걸린다.

채점표 — PCTFREE만 다른 다섯 테이블 ​

모두 10만 행이고 최종 데이터는 전부 같다. 만드는 방법만 다르다.

만든 방식UPDATE 전 블록이전행이전율인덱스 경유 Buffers☐
PCTFREE 0 + 나중에 UPDATE1,00076,16976.2%30,549☐
PCTFREE 10 + 나중에 UPDATE1,12673,49473.5%29,482☐
PCTFREE 40 + 나중에 UPDATE1,63056,98457.0%23,083☐
PCTFREE 75 + 나중에 UPDATE3,77200%786☐
처음부터 최종 길이로 적재3,52000%735☐

눈으로 짚을 것 ​

D *(공개 사이트에는 없음)* 전체 스캔 비교 — 3,904 vs 3,469
    ☐ 7만 6천 행이 이사를 갔는데 왜 1.13배밖에 안 되는가?
      -> 전체 스캔은 어차피 전부 읽는다. 쪽지를 따라갈 필요가 없다

D *(공개 사이트에는 없음)* 인덱스 경유 비교 — 30,549 vs 735
    ☐ INDEX RANGE SCAN 줄은 양쪽 다 45 인 것을 확인
    ☐ 차이가 전부 TABLE ACCESS BY INDEX ROWID 에서 난다는 것을 확인
    ☐ "행 이전은 인덱스 경유에서만 드러난다" 를 숫자로 말할 수 있는가?

D *(공개 사이트에는 없음)* table fetch continued row — 15,252 vs 0
    ☐ 2만 건 조회에 15,252번을 더 걸었다. 이름이 뜻 그대로다

[E] MOVE 후 — chain_cnt 0 인데 Buffers 가 735 가 아니다
    ☐ CLUSTERING_FACTOR 약 52,200 vs 3,449 를 확인 (이 둘만 실행 환경에 따라 조금 흔들린다)
    ☐ "MOVE 는 모양을 고치지 순서를 안 고친다" 를 설명할 수 있는가?

[F] 행 연결 — COUNT(C1) 15,207 vs COUNT(C3) 25,207
    ☐ 첫 컬럼만 읽으면 continued row 가 0 인 것을 확인
    ☐ 그래서 "자주 읽는 컬럼을 앞에" 라는 규칙이 나온다

☠️ 여기서 교과서가 뭉뚱그리는 지점 ​

"행 이전"과 "행 연결"은 둘 다 CHAIN_CNT 컬럼 하나에 잡히지만 다른 현상이다.

행 이전행 연결
원인블록에 자리가 없다행이 블록보다 크다
PCTFREE로 막히나막힌다 (문턱만 넘으면)안 막힌다
MOVE로 고쳐지나고쳐진다 (CF는 못 돌려받는다)안 고쳐진다

자세한 내용은 2_파고들기 §6에 있다.


STEP 5 — VARCHAR2(4000)을 재판한다 (10분) ​

bash
docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1 < 03_VARCHAR2_4000.sql
powershell
Get-Content 03_VARCHAR2_4000.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s sqlp/sqlp@localhost/FREEPDB1

먼저 유죄 판결문을 써 보자 ​

"VARCHAR2(4000) 은 나쁘다. 왜냐하면 ______________________________ 때문이다."
▶ 돌린 뒤에 펼치기

대부분 "공간을 낭비하니까"라고 쓴다. 실측 결과는 다르다.

무엇을 재나VARCHAR2(4000)알맞게 선언
블록874874
AVG_ROW_LEN2323
전체 스캔 Buffers821821

공간은 한 바이트도 더 안 쓴다. VARCHAR2는 가변 길이다.

진짜 죄목은 세 가지다.

  1. 통계가 없으면 선언 길이가 그대로 비용이 된다. 정렬 Cost가 59,755 vs 1,401(42.7배), E-Bytes가 272M vs 4,810K로 갈린다. 실제로 읽은 Buffers는 822로 똑같다. 틀린 건 속도가 아니라 오라클의 눈이다.
  2. 인덱스 키 길이를 잡아먹는다. (VARCHAR2(4000), VARCHAR2(4000)) 인덱스에 긴 값을 넣으면 ORA-01450: maximum key length (6397) exceeded 에러가 난다. 느려지는 정도가 아니라 적재가 죽는다.
  3. 언젠가 누군가 그 4000자를 채운다. 그 순간 STEP 4의 행 이전과 행 연결이 시작된다.

STEP 6 — T1 리포트 3호 ★ 오늘의 산출물 ​

양식은 T1_단건SQL_튜닝리포트.md를 따른다.

이번 호는 성격이 다르다. SQL은 한 글자도 고치지 않았다. 고친 것은 저장 구조와 보관 정책이다. 그래서 「조치」 칸에는 SQL 리비전 대신 DDL과 정책이 들어간다.

┌──────────────────────────────────────────────────────────────────┐
│ T1 단건 SQL 튜닝 리포트 — 3호                                     │
├──────────────────────────────────────────────────────────────────┤
│ 대상        : T_ORD_LOG 주문상태이력 조회 (정산 현업 조민우)      │
│ 측정 일시   : ____________    측정 조건 : 단독 세션 · 1회 실행     │
│ 리비전      : (없음 — SQL 미변경. 저장 구조 변경)                 │
├──────────────────────────────────────────────────────────────────┤
│ 1. 현상                                                           │
│    이력 95%(475,025행) 삭제 후에도 조회 Buffers 3,602 → 3,602     │
│ 2. 원인                                                           │
│    ______________________________________________________________ │
│ 3. 조치                                                           │
│    즉시 : ______________________________________________________  │
│    근본 : ______________________________________________________  │
│ 4. 효과 (Buffers 로)                                              │
│    ______________________________________________________________ │
│ 5. 리스크  ★ 비우면 반려된다                                      │
│    ______________________________________________________________ │
│ 6. 회귀 검증                                                      │
│    ______________________________________________________________ │
└──────────────────────────────────────────────────────────────────┘

2번 「원인」에 들어가야 할 것 ​

  • DELETE는 행을 지울 뿐 고수위선을 내리지 않는다
  • 전체 스캔은 고수위선까지 읽는다(FULL 블록이 0개, FS4가 3,123개인데도 전부 읽힌다)
  • USER_SEGMENTS.blocks 3,712와 USER_TABLES.blocks 3,665 모두 DELETE 전후가 같다

3번 「조치」 — 즉시와 근본을 나눠 쓴다 ​

쓸 것
즉시ENABLE ROW MOVEMENT + SHRINK SPACE. 야간 수행. Buffers 3,602 → 183
근본보관을 DELETE로만 하는 정책 자체를 바꾼다: 파티션 또는 아카이브 테이블 + TRUNCATE
LOG_ST VARCHAR2(4000)에 코드와 설명을 같이 담는 설계를 분리한다(행 이전의 원인)

5번 「리스크」에 반드시 들어가야 할 것 ​

이번 호는 리스크 칸이 본문보다 중요하다. 이 칸이 14화로 가는 청구서다.

  • SHRINK/MOVE는 행을 전부 다시 쓴다. redo가 생기고, 마지막 순간에 테이블 전체를 잠근다. 월말 배치 창에 끼워 넣어야 한다
  • 다음 달에 또 같은 일이 생긴다. DELETE 보관 정책이 그대로인 한 이 작업은 치료가 아니라 매달 반복되는 청소다
  • MOVE를 쓰면 인덱스가 UNUSABLE 상태가 된다. REBUILD를 빠뜨리면 ORA-01502 장애가 난다
  • ENABLE ROW MOVEMENT는 ROWID가 바뀌어도 좋다는 허락이다. ROWID를 저장해 쓰는 코드가 있으면 깨진다
  • 02화에서 만든 인덱스 2개가 48MB다(IX_ORD_BIG_DT 22MB + IX_ORD_BIG_DT_AMT 26MB). 테이블(47MB)보다 크다. 적재할 때마다 같이 갱신된다 → 14화
  • T_ORD_BIG에도 고수위선 아래 빈 블록 110개(5,923 − 5,813)가 이미 있다

6번 「회귀 검증」 ​

확인할 것방법
SHRINK 후 행수가 그대로인가SELECT COUNT(*) 전후 비교 (24,975)
결과가 같은가조치 전후 COUNT(*), MAX(LOG_DT) 비교
MOVE를 썼다면 인덱스가 살아 있나SELECT status FROM user_indexes로 VALID인지 확인
ROWID를 쓰는 코드가 있나애플리케이션 검색. 있으면 SHRINK 금지

STEP 7 — 블록을 열어 본다 (선택 · 10분) ​

SYSDBA 권한이 필요하다. 시간이 없으면 건너뛰어도 된다. 운영 DB에서는 함부로 하면 안 된다. 트레이스 파일이 쌓이고, DBA 승인을 받아야 하는 작업이다. 전제: STEP 4를 먼저 돌려야 한다(T_MIG10과 CHAINED_ROWS가 있어야 한다).

bash
MSYS_NO_PATHCONV=1 docker exec -i ora-hanorder sqlplus -s / as sysdba < 90_블록덤프_SYSDBA.sql
powershell
Get-Content 90_블록덤프_SYSDBA.sql -Encoding UTF8 | docker exec -i ora-hanorder sqlplus -s "/ as sysdba"

Git Bash에서 MSYS_NO_PATHCONV=1을 빼면 /를 경로로 바꿔 버려서 접속이 안 된다.

스크립트를 돌리면 트레이스 파일 경로가 나온다. 그 파일에서 네 군데만 본다.

보는 곳실측 예뜻
itc: 22ITL 슬롯 수. 이 블록을 동시에 고칠 수 있는 트랜잭션 수
0x02 ... --U- 100--U- / Lck 100커밋됐지만 정리 전 · 행 100개를 잠갔던 기록
nrow=100 · avsp=0x2행 디렉터리 항목 수 · 남은 빈 공간 2바이트
tl: 9 fb: --H----- + nrid:★ 이사 간 행. 9바이트 쪽지 하나만 남았다
tl: 268 fb: --H-FL--멀쩡한 행. 머리(H)·첫조각(F)·끝조각(L) 다 있음
bash
# 뽑아 보기
docker exec -i ora-hanorder sh -c "grep -nE 'itc:|^Itl|^0x0[12] |nrow=|avsp=|^tl: |^nrid:' <경로>"

☐ ROWID는 머리를 가리킨다. 몸이 이사를 가도 ROWID는 바뀌지 않는다. 그래서 인덱스를 고칠 필요가 없고, 그래서 조회가 두 번 간다. STEP 4의 30,549는 이 한 문장으로 설명된다.


STEP 8 — 서술 답안 (400~600자) ​

조민우 씨에게 보낼 회신을 쓴다. 아침에 "확인해 보고 연락드리겠습니다"라고 했으니 답을 줘야 한다.

4단계 프레임(현상/진단 → 원인 → 개선안 → 근거/효과)은 01화 3_실습과_기록.md와 같다.

▶ 선배의 첨삭 포인트 (쓰고 나서)

① "데이터를 지워도 안 빨라집니다"로 끝내면 반쪽이다. 현업이 묻는 것은 왜가 아니라 그래서 언제 빨라지나다. 조치와 일정을 같이 적는다.

② 현업이 알아듣는 말로 쓴다. "고수위선이 안 내려갔습니다"로는 뜻이 전달되지 않는다. "창고 선반에서 서류만 버리고 상자는 그대로 둔 상태라, 점검하는 사람은 여전히 모든 상자를 열어 봅니다"라고 옮겨야 한다.

③ 근본 원인을 숨기지 않는다. 이번 달에 SHRINK로 183을 만들어도 다음 달에 또 똑같아진다. 그 사실을 적지 않으면 다음 달에 똑같은 전화를 받게 되고, 그때는 그 책임을 떠안게 된다.

④ 숫자는 Buffers로 쓴다. "20배 빨라졌습니다"가 아니라 "조회 한 번에 읽는 블록이 3,602에서 183으로 줄었습니다"라고 쓴다. 여기에 "행을 95% 지운 것만으로는 3,602에서 3,602로, 전혀 줄지 않았습니다"를 같이 적어야 조치의 가치가 드러난다.


STEP 9 — 파인만 자가설명 ​

절차는 01화와 같다. 1단 백지 설명 → 2단 막힘 태그(최소 1개) → 3단 원천 복귀 → 4단 재설명 순서로 진행한다.

오늘 자주 나오는 태그 세 가지

태그전형적인 문장
#인과"왜 DELETE가 고수위선을 안 내리는지 설명하다 막혔다" → §3
#용어"행 이전과 행 연결의 차이를 말로 못 하겠다" → §6
#수치"전체 스캔은 1.13배인데 인덱스 경유는 41.6배인 이유를 못 세겠다" → §6의 두 실행계획을 나란히 놓고 45블록 줄을 찾아본다

4단 되묻기 3문 (오늘 버전) ​

  1. 조건 반전: "고수위선이 성능에 도움이 되는 경우가 있나?" (힌트: 멀티블록 읽기와 INSERT 경로)
  2. 반례 요구: "SHRINK SPACE를 하면 안 되는 테이블을 하나 든다면?"
  3. 측정 지목: "'이 테이블에 행 이전이 있다'를 증명하려면 무엇을 재야 하나? 두 가지를 꼽아 보자."

태그는 _막힘로그.md로 옮긴다.


완료 체크리스트 ​

  • [ ] STEP 0: 이 화가 14화로 보낼 청구서 세 줄을 먼저 적었다
  • [ ] STEP 1: 보기 전에 예측 4개를 적었다
  • [ ] STEP 2: [A]~[I]를 돌리고 3,602 → 3,602 → 183 → 1을 확인했다
  • [ ] STEP 2: COMPACT가 FULL을 179로 만들고도 Buffers는 바꾸지 못하는 것을 눈으로 짚었다
  • [ ] STEP 3: 6,016 / 5,923 / 5,826 / 5,813 네 숫자의 차이를 각각 설명했다
  • [ ] STEP 3: ROWID 네 조각에 테이블스페이스가 없다는 것을 세 가지 증거로 말할 수 있다
  • [ ] STEP 4: 735 vs 30,549를 확인하고, INDEX RANGE SCAN 줄이 양쪽 다 45인 것을 짚었다
  • [ ] STEP 4: MOVE 후에도 735가 아닌 이유(CF 약 52,200)를 적었다
  • [ ] STEP 5: VARCHAR2(4000)의 진짜 죄목 세 가지를 적었다
  • [ ] STEP 6: T1 리포트 3호를 썼고, 리스크 칸에 14화 청구서를 명시했다
  • [ ] STEP 8: 조민우 씨 회신을 문장으로 풀어 썼다("다음 달에 또 그렇게 된다"를 포함했는가)
  • [ ] STEP 9: 막힘 태그를 최소 1개 _막힘로그.md에 옮겼다

완결성 게이트: STEP 6의 리스크 칸과 STEP 9의 태그가 비어 있으면 이 화는 미완성이다.


실습 뒷정리 ​

이 화의 실습 테이블은 다음 화에 필요 없다. 다 쓴 뒤 지워도 된다. 각 스크립트가 맨 앞에서 알아서 지우므로 꼭 할 필요는 없다.

sql
BEGIN
  FOR i IN (SELECT table_name FROM user_tables
             WHERE table_name IN ('T_ORD_LOG','T_MIG00','T_MIG10','T_MIG40','T_MIG75',
                                  'T_MIG_OK','T_CHAIN','T_W4000','T_W30','CHAINED_ROWS')) LOOP
    EXECUTE IMMEDIATE 'DROP TABLE '||i.table_name||' PURGE';
  END LOOP;
END;
/

⚠️ T_ORD_BIG, T_ORD, T_ORD_DET와 인덱스 2개는 절대 건드리면 안 된다. 다음 화에서 그대로 쓴다.


다음 화로 넘기는 상태 ​

무엇값
T_ORD_BIG변경 없음. 100만 행 · 인덱스 2개 · HWM 아래 5,923블록
새로 만든 빚보관을 DELETE로만 하는 정책: 매달 고수위선이 다시 올라간다
기록해 둔 수치3,602 → 3,602 → 183 · 인덱스 2개 48MB · 빈 블록 110개
다시 확인한 것MOVE로도 돌아오지 않는 CF. 04화에서 본 원리 그대로다(ORDER BY로 다시 쌓아야 고쳐진다)
열어 둔 질문ITL 슬롯이 모자라면 → 12화 · 13화

다음 → 06화 「100만 번의 왕복」: 오늘은 한 테이블 안에서 블록을 몇 개 읽는지를 봤다. 다음 화에서는 두 테이블 사이를 몇 번 왕복하는지를 본다.