424. 클러스터드 인덱스 (Clustered Index)
⚠️ 이 문서는 인덱스(목차)를 찾고 나서 데이터를 찾으러 또다시 디스크로 점프(Key Lookup)해야 하는 넌클러스터드 인덱스의 느린 속도를 완벽하게 해결하기 위해, **아예 인덱스의 리프 노드에 '진짜 데이터'를 통째로 심어놓고 물리적으로 정렬시켜버리는 극강의 검색 구조인 '클러스터드 인덱스'**를 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: 클러스터드 인덱스는 목차와 본문이 합쳐진 구조다. 데이터가 입력되는 순간, 인덱스의 정렬 순서(보통 Primary Key 순서)에 맞춰 하드디스크의 실제 데이터 위치까지 물리적으로 똑같이 재배열된다.
- 가치: 인덱스를 타고 바닥(리프 노드)에 도착하는 순간 그 자리에 진짜 데이터가 100% 들어있기 때문에, 추가적인 디스크 점프(Random Access)가 필요 없어 검색 속도가 무시무시하게 빠르다.
- 한계: 물리적인 데이터의 순서를 결정짓는 유일한 기준이므로, 테이블당 오직 딱 1개만 만들 수 있다. (일반적으로 기본 키(PK)에 자동으로 생성된다.)
Ⅰ. 개요: 목차가 곧 본문이다 (Context & Necessity)
"아이디가 5번인 회원 데이터를 찾아줘!"
- 넌클러스터드 인덱스(423번 문서): 인덱스를 타서 5번을 찾았더니, "하드디스크 102번 방에 데이터가 있어요"라고 주소를 준다. 거기로 또 달려가야 한다. (느림)
클러스터드 인덱스는 아예 디스크 구조 자체를 인덱스 순서대로 뜯어고쳐 버렸다.
- 인덱스를 타서 5번을 찾았다.
- 그 자리에
[ID:5, 이름:김철수, 나이:20]이라는 진짜 데이터가 통째로 박혀있다! - 즉시 데이터를 리턴한다. 추가 점프가 0번이다. (가장 빠름)
📢 섹션 요약 비유: 클러스터드 인덱스는 **'영어사전(사전 그 자체)'**과 같습니다. 영어사전은 단어가 알파벳순(A~Z)으로 물리적으로 완벽하게 정렬되어 있죠. 'Apple'을 찾기 위해 목차를 보고 다시 몇 페이지로 점프할 필요가 없습니다. 'A'가 있는 페이지를 펴면 거기에 바로 Apple의 뜻(데이터)이 적혀있으니까요.
Ⅱ. 클러스터드 인덱스의 3대 특징 ★
시험에서 넌클러스터드 인덱스와 비교하는 문제로 100% 출제된다.
1. 리프 노드 = 실제 데이터 (Data Page)
- B-Tree의 맨 아랫단인 리프 노드에 '주소'가 아니라 **'행(Row) 데이터 전체'**가 통째로 저장되어 있다.
2. 물리적 정렬 (Physical Sorting)
- 이 인덱스를 기준으로 하드디스크에 저장된 진짜 데이터들의 순서가 1번부터 100만 번까지 완벽하게 오름차순 정렬된다.
- 장점:
BETWEEN 10 AND 20같은 범위 검색을 할 때, 10번부터 20번까지 디스크에 옹기종기 모여있으므로(Clustered) 한 번에 싹 긁어올 수 있어 속도가 어마어마하게 빠르다.
3. 테이블당 단 1개만 존재 가능
- 물리적인 데이터의 순서는 두 가지일 수 없다. (사전이 알파벳순이면서 동시에 길이순으로 정렬될 수는 없는 것과 같다.)
- 대부분의 RDBMS(MySQL의 InnoDB 등)는 테이블 생성 시 지정한 **기본 키(Primary Key)**를 이 클러스터드 인덱스로 자동 지정한다.
Ⅲ. 실무 팁: PK를 잘못 잡으면 벌어지는 참사
클러스터드 인덱스는 쓰기(INSERT) 작업에 매우 민감하다.
데이터를 삽입할 때마다 '물리적 순서'를 끼워 맞춰야 하기 때문이다.
- 나쁜 PK 설계 (
UUID나 랜덤 문자열)- 1번 데이터, 9번 데이터가 있는데 갑자기 5번 데이터가 Insert 되었다.
- 디스크는 물리적 순서를 맞추기 위해 9번 데이터를 뒤로 밀어내고 5번을 중간에 억지로 끼워 넣어야 한다. (Page Split 현상 발생, 디스크 성능 폭락)
- 좋은 PK 설계 (
Auto Increment등 순차 증가값)- 1, 2, 3번이 있고 4번이 들어온다.
- 중간에 끼워 넣을 필요 없이 맨 뒤에 그냥 갖다 붙이면 된다. (최고의 성능)
- 그래서 MySQL에서 PK를 설계할 때는 무조건 순서대로 커지는 숫자(Auto Increment)를 쓰라고 권장하는 것이다.
┌──────────────────────────────────────────────────────────────┐
│ 클러스터드 인덱스(Clustered Index) 작동 구조 시각화 │
├──────────────────────────────────────────────────────────────┤
│ │
│ [ 📑 인덱스 트리 (ID 기준 = PK) ] [ 💾 실제 데이터 블록 (물리적 정렬) ] │
│ ┌─────[5]──────┐ │ │
│ ▼ ▼ │ 1번방: [ID:1, 박민수, 22세] │
│ [1, 3] [7, 9] ────▶ │ 2번방: [ID:3, 최보스, 40세] │
│ │ │ │ 3번방: [ID:5, 김철수, 30세] │
│ ▼ ▼ │ 4번방: [ID:7, 김가루, 20세] │
│ [진짜데이터] [진짜데이터] │ 5번방: [ID:9, 이영희, 25세] │
│ (리프노드) (리프노드) │ │
│ │
│ ★ 특징: 인덱스의 리프 노드가 곧 실제 데이터가 저장된 물리적 디스크 방이다. │
│ 새로 ID:4가 들어오면 3번방과 5번방 사이를 찢고 들어가야 해서 무겁다. │
└──────────────────────────────────────────────────────────────┘
Ⅳ. 결론
"가장 자주 찾는, 그리고 가장 넓게 찾는 컬럼에 클러스터드 인덱스를 허락하라."
테이블당 딱 1개만 주어지는 이 황금 티켓을 어디에 쓸 것인가는 데이터베이스 설계의 핵심이다. 단순히 기계가 자동으로 달아주는 대로 PK에 둘 수도 있지만, 고수들은 비즈니스 로직을 분석하여 "사용자들이 가장 넓은 범위를 한 번에 검색(BETWEEN)하는 컬럼(예: 결제 날짜)"으로 클러스터드 인덱스를 의도적으로 변경하기도 한다. 이 강력한 '물리적 정렬'의 힘을 통제하는 자만이 대용량 트래픽의 병목을 뚫어낼 수 있다.
📌 관련 개념 맵
- 대척점 개념: Non-Clustered Index (423번 문서 - 여러 개 생성 가능, 포인터 점프 발생)
- 내부 엔진 (MySQL): InnoDB는 Clustered Index (Index-Organized Table) 구조를 기본으로 씀.
- 발생하는 문제: Page Split (페이지 분할 - 중간에 데이터가 끼어들 때 발생하는 성능 저하)
- 생성 조건: Primary Key 제약조건 추가 시 1순위로 생성됨.
👶 어린이를 위한 3줄 비유 설명
- 클러스터드 인덱스는 선생님이 반 친구들 30명을 운동장에 '키 순서대로' 직접 줄 세우는 거예요. (물리적 정렬)
- 키가 150cm인 친구를 찾으려면, 그냥 중간쯤 가서 보면 그 자리에 진짜 150cm 친구가 서 있죠. (추가 점프 없음)
- 하지만 전학생이 오면, 자기 키에 맞는 자리를 찾아서 비집고 들어가야 하니까 줄 서 있는 친구들이 다 같이 옆으로 한 칸씩 이동해야 해서 조금 힘들답니다!