Skip to content

02화 · 인덱스는 있는데 안 탄다 ​

🗓️ 3월 11일 (월) · 01화에서 일주일 뒤 · 무대 ora-hanorder오늘 배울 것: 인덱스는 정렬된 목록이다. 그리고 오늘은 두 번 틀린다.


파일 세 개 ​

파일무엇을 하나시간
읽는다1_사건.md인덱스를 만들었는데 안 타고, 고쳤는데 또 안 타다가, 결국 64배 빨라지는 하루30분
한다3_실습과_기록.md6단계 실험 · 무력화 6종 · T1 리포트 1호60~90분
찾는다2_파고들기.mdB*Tree · 스캔 6종 · Sargable 교정표 · 커버링 · CF 맛보기필요할 때

1을 읽고 3을 따라 한다. 2는 막힐 때 펼친다. 시간이 없는 주에는 1_사건을 중단 지점 1까지 읽고 3_실습은 STEP 0, 1, 2, 5만 한다(약 40분).


지난 화에서 들고 오는 것 ​

Q1 = 5,827블록6월 주문 27,390건을 세려고 테이블 전체를 읽는다
T_ORD_BIG 인덱스0개
지난주 내 가설"100만 건인데 인덱스가 0개라서 느리다. 만들면 된다"

그리고 박팀장에게서 메시지가 하나 와 있다.

"지난주 보고서 잘 봤습니다. 그런데 결론이 '아직 고치지 않았습니다'로 되어 있던데, 그래서 언제쯤 빨라지나요?"


오늘의 전개 — 두 번 틀리고 한 번 이긴다 ​

한 일결과
1차ORD_DT에 인덱스를 만들었다5,826. 그대로. 힌트를 줘도 안 탄다
2차TO_CHAR 가공을 없앴다(rev01)5,827. 그대로. 그런데 이번에는 오라클이 옳다
—억지로 인덱스를 태워 봤다27,466. 4.7배 느려졌다
3차테이블을 읽을 이유를 없앴다(rev02)91. 64배.

왜 두 번이나 틀리게 짰을까? "인덱스를 만들면 빨라진다"는 믿음은 한 번은 깨져야 하기 때문이다. 오늘 깨지지 않으면 04화에서 더 크게 깨진다.


오늘 배우는 한 문장 ​

인덱스는 빨리 찾는 마법이 아니라 정렬된 목록이다. 조건이 정렬된 순서에서 "여기부터 여기까지"를 지목할 수 있으면 access, 지목하지 못하면 filter다.

무력화 6종(컬럼 가공, 묵시적 형변환, 선두 %LIKE, 부정형, IS NULL, 선두 컬럼 누락)도 모두 이 한 문장으로 설명할 수 있다.


🔑 오늘의 비유 — 방문객 출입대장 ​

안내 데스크 캐비닛에 종이 바인더로 된 출입대장이 있다. 방문 일시 순으로 적혀 있어서 6월 방문자를 세려면 6월 1일 첫 줄을 찾아 7월 1일이 나오기 전까지만 보면 된다. 1월부터 5월까지는 펴 볼 필요도 없다. 그런데 "날짜를 여덟 자리 숫자로 바꿔서 세라"라고 하면 사정이 달라진다. 대장에는 20240601이라고 적힌 줄이 없으니, 첫 줄부터 한 줄씩 바꿔 봐야 한다.

방문객 출입대장오라클
방문 일시 순으로 적힌 바인더인덱스: 키 순서로 정렬된 목록(IX_ORD_BIG_DT)
6월 1일 첫 줄을 찾아 7월 1일 전까지INDEX RANGE SCAN: 조건이 access로 범위를 지목한다
1월~5월은 펴 보지 않는다읽지 않은 블록만큼 Buffers가 줄어든다
"여덟 자리 숫자로 바꿔서 세라"컬럼 가공 TO_CHAR(ORD_DT): 대장(인덱스)에는 그런 모양의 값이 없다
첫 줄부터 한 줄씩 바꿔 보며 세기filter: 다 읽고 버린다. 인덱스가 있어도 FULL로 읽는다

01화의 비유도 다시 나온다. 커피 캐리어(블록, 한 캐리어에 169건)다.


☠️ 오늘의 함정 — 빠른데 틀린 코드 ​

TO_CHAR를 없애려다 보면 이렇게 쓰고 싶어진다.

sql
WHERE ORD_DT BETWEEN DATE '2024-06-01' AND DATE '2024-06-30'

T_ORD_BIG에서 돌려 보면 결과가 똑같다. 테스트도 통과한다. 그런데 옆 테이블 T_ORD에 같은 코드를 쓰면 137건, 34,159,700원이 사라진다.

반면 강도현의 TO_CHAR 원본은 T_ORD에서도 정확하다. 강도현의 코드는 느릴 뿐, 답은 맞다.

느린 코드를 빠르게 만드는 것이 튜닝이고, 맞는 코드를 틀리게 만드는 것은 장애다.


실습 준비 ​

bash
docker start ora-hanorder

01화를 마친 상태(T_ORD_BIG에 인덱스 0개)에서 시작한다. 실습 스크립트는 맨 앞에서 인덱스를 지우고 시작하므로 몇 번을 돌려도 결과가 같다.

스크립트무엇
실습/00_인덱스_실험.sql6단계 [A]~[F]. 오늘 실습의 본체
실습/01_무력화_6종.sql무력화 패턴과 교정형을 나란히 측정
실습/02_경계값_검증.sql회귀 검증. 빠르게 고친 뒤에도 답이 그대로인가

리비전은 리비전/에 Q1_rev00 → rev01 → rev02 순서로 남는다.


이 화의 산출물 ​

무엇어디
T1 단건 SQL 튜닝 리포트 1호 ★ (Q1 rev00 → rev02 · Buffers 5,827 → 91)3_실습 STEP 5 · T1 양식
Q1_rev00 → rev01 → rev02: 커버링 인덱스 (ORD_DT, ORD_AMT)까지리비전/

이 화가 다음으로 넘기는 것 ​

무엇어디로
CF = 1,000,000 (27,466의 정체)04화: 커피 캐리어가 다시 나온다
손익분기점은 몇 %인가04화: 오늘 만든 인덱스로 범위를 넓혀 간다
인덱스 2개의 적재 비용14화: 청구서가 날아온다
컬럼 가공을 지울 수 없을 때03화: ora-dist는 날짜가 VARCHAR2(8)이다
E-Rows가 정확해도 틀리는 경우10화: 히스토그램

← 01화 「인수인계 없는 인수인계」 · 교재 전체 안내 · 다음 → 03화 「날짜가 문자로 박혀 있다」