420. 옵티마이저 (Optimizer) - CBO와 시스템 통계

⚠️ 이 문서는 사용자가 엉망진창으로 작성한 SQL 쿼리문을 받아 들고, 데이터베이스 내부에서 **"어떤 길(인덱스)을 타야 가장 빨리 데이터를 가져올 수 있을까?"를 스스로 고민하고 결정하는 데이터베이스의 천재 두뇌인 '옵티마이저'**를 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 옵티마이저는 SQL(What)을 입력받아, 가장 비용(Cost)이 적게 드는 최적의 실행 계획(How)을 짜내는 네비게이션 엔진이다.
  2. 종류: 과거에는 정해진 규칙(RBO)에 따라 기계적으로 길을 찾았지만, 현대의 DB는 데이터의 통계 정보(행의 개수, 분포도 등)를 바탕으로 스스로 계산하는 **비용 기반 옵티마이저(CBO)**를 표준으로 사용한다.
  3. 가치: 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줄 비유 설명

  1. 옵티마이저는 100만 개의 장난감 상자 중에서 '빨간 자동차'를 가장 빨리 찾는 방법을 고민하는 대장 요정이에요.
  2. 예전(RBO)에는 "무조건 첫 번째 상자부터 뒤져라!"라는 규칙만 따랐죠.
  3. 하지만 지금(CBO)은 "어제 통계 보니까 세 번째 상자에 빨간 장난감이 90% 몰려있더라! 거기를 먼저 뒤져!"라고 똑똑하게 계산해서 움직인답니다!