420. 옵티마이저 (Optimizer) - CBO와 시스템 통계
⚠️ 이 문서는 사용자가 엉망진창으로 작성한 SQL 쿼리문을 받아 들고, 데이터베이스 내부에서 **"어떤 길(인덱스)을 타야 가장 빨리 데이터를 가져올 수 있을까?"를 스스로 고민하고 결정하는 데이터베이스의 천재 두뇌인 '옵티마이저'**를 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: 옵티마이저는 SQL(What)을 입력받아, 가장 비용(Cost)이 적게 드는 최적의 실행 계획(How)을 짜내는 네비게이션 엔진이다.
- 종류: 과거에는 정해진 규칙(RBO)에 따라 기계적으로 길을 찾았지만, 현대의 DB는 데이터의 통계 정보(행의 개수, 분포도 등)를 바탕으로 스스로 계산하는 **비용 기반 옵티마이저(CBO)**를 표준으로 사용한다.
- 가치: CBO가 똑똑하게 작동하려면 반드시 **최신 '시스템 통계 정보(Statistics)'**가 필요하다. 통계가 옛날 것이면 옵티마이저는 엉뚱한 길로 안내하여 서버를 터뜨린다.
Ⅰ. 개요: 100만 개의 길 중 하나를 고르는 법 (Context & Necessity)
"서울에서 부산으로 가는 가장 빠른 길을 찾아줘!"
- 10년 전 네비게이션(RBO): "무조건 고속도로가 국도보다 빠르니까 고속도로로 안내할게." (도로가 막히든 말든 무조건 규칙대로)
- 최신 네비게이션(CBO): "지금 고속도로에 차가 10만 대가 넘네? 차라리 국도로 돌아가는 게 30분 더 빠르겠다. 국도로 안내할게!" (실시간 통계를 바탕으로 계산)
데이터베이스도 똑같다.
SELECT * FROM Users WHERE age = 20 이라는 쿼리를 쳤을 때, age 컬럼에 인덱스가 걸려 있어도 옵티마이저는 인덱스를 안 탈 수 있다.
- 만약 100만 명의 유저 중 90만 명이 20살이라면?
- 옵티마이저: "인덱스 책갈피를 90만 번 들춰보느니, 그냥 처음부터 끝까지 다 읽는 게(Full Scan) 낫겠다!" 이것이 **비용 기반 옵티마이저(CBO, Cost-Based Optimizer)**의 위력이다.
📢 섹션 요약 비유: 옵티마이저는 **'내비게이션'**이고, 통계 정보는 실시간 **'교통 상황(CCTV)'**입니다. 내비게이션이 아무리 똑똑해도 CCTV가 고장 나서 어제 찍힌 텅 빈 도로 사진만 보고 있다면, 꽉 막힌 길로 우리를 안내하겠죠?
Ⅱ. RBO vs CBO 비교 ★
| 구분 | 규칙 기반 (RBO: Rule-Based) | 비용 기반 (CBO: Cost-Based) |
|---|---|---|
| 판단 기준 | 데이터베이스에 내장된 '우선순위 룰' | 데이터의 '통계 정보(행의 수, 분포도)' |
| 특징 | 인덱스가 있으면 무조건 인덱스를 탄다. | 계산해 보고 인덱스보다 풀스캔이 빠르면 풀스캔을 탄다. |
| 속도 예측 | 불가능 (데이터가 많아지면 엉망이 됨) | 데이터양에 맞춰 항상 최적의 경로를 찾음 |
| 현재 위상 | 구시대의 유물 (거의 안 씀) | 현대 RDBMS의 절대 표준 |
Ⅲ. CBO의 핵심: 시스템 통계 (Statistics)
CBO는 마법사가 아니다. **"이 테이블에 데이터가 몇 건 있니? 데이터 종류는 몇 가지니?"**라는 정보(통계)가 있어야만 비용을 계산(Costing)할 수 있다.
이 통계 정보는 시스템 카탈로그(394번 문서)에 저장된다.
- 테이블 통계: 행(Row)의 총개수, 테이블이 차지하는 디스크 블록 수
- 컬럼 통계: 컬럼 값의 최대/최솟값, 데이터의 분포도(Histogram)
- 인덱스 통계: 인덱스 트리의 깊이(Height), 고유한 값의 개수
🚨 DBA의 가장 중요한 임무: 통계 갱신
테이블에 데이터를 1,000만 건이나 Insert 했는데 통계를 업데이트하지 않았다면?
옵티마이저는 아직도 데이터가 0건인 줄 알고 바보 같은 실행 계획을 짠다.
그래서 DBA는 주기적으로 틈이 날 때마다 ANALYZE TABLE (또는 오라클의 DBMS_STATS) 명령어를 돌려서 옵티마이저에게 최신 맵(Map)을 쥐여주어야 한다.
┌──────────────────────────────────────────────────────────────┐
│ 비용 기반 옵티마이저 (CBO)의 실행 계획 생성 과정 시각화 │
├──────────────────────────────────────────────────────────────┤
│ │
│ [ 👨💻 사용자 ] "SELECT * FROM Orders WHERE status='취소';" │
│ │ │
│ ▼ │
│ ┌──────────────────────────┐ │
│ │ 🧠 옵티마이저 (CBO) │ ◀── [ 📊 시스템 통계 (카탈로그) ] │
│ │ │ - Orders 테이블 총 100만 건 │
│ │ │ - '취소' 상태는 단 10건 존재함 │
│ │ (경로 1) Full Scan 예상 비용 : 1000 │
│ │ (경로 2) Index Scan 예상 비용 : 5 🏆 (당첨!) │
│ └──────────────────────────┘ │
│ │ │
│ ▼ │
│ [ 📜 실행 계획 (Execution Plan) ] │
│ "좋아, 인덱스를 타서 10건만 쏙 뽑아오자!" │
└──────────────────────────────────────────────────────────────┘
Ⅳ. 결론
"느린 쿼리의 90%는 코드가 아니라 옵티마이저와의 소통 부재에서 온다." 우리가 SQL 튜닝을 한다고 쿼리를 이리저리 꼬아서 쓰는 것은 결국 "옵티마이저가 내가 원하는 인덱스를 타도록 유도하는" 두뇌 싸움이다. 가끔 옵티마이저가 멍청한 짓을 할 때는 '힌트(Hint)'를 줘서 강제로 길을 지정해 줄 수도 있지만, 근본적인 해결책은 항상 시스템 통계 정보가 최신 상태인지 확인하는 것이다. 옵티마이저는 데이터베이스 엔진의 꽃이자, 선배 엔지니어들이 수십 년간 갈아 넣은 수학적 최적화의 결정체다.
📌 관련 개념 맵
- 후행 과정: 실행 계획 (Execution Plan - 421번 문서)
- 참고 저장소: 시스템 카탈로그 (394번 문서)
- SQL 튜닝 기법: Hint (힌트 -
/*+ INDEX(table_name index_name) */) - 핵심 명령어:
ANALYZE TABLE(통계 수집 명령어)
👶 어린이를 위한 3줄 비유 설명
- 옵티마이저는 100만 개의 장난감 상자 중에서 '빨간 자동차'를 가장 빨리 찾는 방법을 고민하는 대장 요정이에요.
- 예전(RBO)에는 "무조건 첫 번째 상자부터 뒤져라!"라는 규칙만 따랐죠.
- 하지만 지금(CBO)은 "어제 통계 보니까 세 번째 상자에 빨간 장난감이 90% 몰려있더라! 거기를 먼저 뒤져!"라고 똑똑하게 계산해서 움직인답니다!