데이터베이스 성능 튜닝을 이야기할 때 가장 먼저 등장하는 개념이 인덱스다. 그중에서도 Cluster Index(클러스터 인덱스)와 Non-Cluster Index(논클러스터 인덱스)는 구조적으로 큰 차이를 가지며, 성능에 영향을 미치는 핵심 요소다. 이 글에서는 두 인덱스가 무엇이며, 어떤 상황에서 어떤 인덱스를 사용해야 하는지 알아보자.
주의: 이 글은 MySQL InnoDB 스토리지 엔진 기준으로 작성되었습니다. SQL Server, PostgreSQL 등 다른 DBMS는 인덱스 구조가 다를 수 있습니다.

Cluster Index는 테이블의 실제 레코드가 인덱스 순서대로 저장되는 구조를 말한다.
쉽게 말해, 클러스터 인덱스는 "책의 본문 페이지가 목차의 순서대로 정렬되어 있는 형태"와 비슷하다.
InnoDB는 다음 우선순위로 클러스터 인덱스를 결정한다:
1. PRIMARY KEY가 있으면 → PK를 클러스터 인덱스로 사용
2. PK가 없고 NOT NULL UNIQUE 인덱스가 있으면 → 첫 번째 UNIQUE 인덱스 사용
3. 둘 다 없으면 → 내부적으로 숨겨진 6바이트 row ID를 자동 생성
따라서 명시적으로 PK를 정의하는 것이 성능과 관리 측면에서 유리하다.
Non-Cluster Index는 인덱스와 실제 데이터가 분리된 구조다.
책 뒤의 색인(index)처럼, 인덱스는 따로 저장되고 그 인덱스가 가리키는 주소로 실제 데이터에 접근하는 방식이다.
| 구분 | Cluster Index | Non-Cluster Index |
|---|---|---|
| 저장 구조 | 테이블 자체가 B+Tree | 별도 인덱스 B+Tree |
| 데이터 정렬 | PK 기준으로 실제 데이터 정렬 | 인덱스만 정렬되고 실제 데이터는 정렬되지 않음 |
| 개수 | 테이블당 1개 | 여러 개 생성 가능 |
| 조회 방식 | 바로 데이터 접근 | PK 검색 후 데이터 접근(테이블 랜덤 액세스) |
| 장점 | 범위 조회 매우 빠름 | 다양한 컬럼 검색 최적화 |
| 단점 | INSERT 시 페이지 분할 발생 가능 | 추가 I/O로 상대적으로 느림 |
PK가 너무 길면 → 모든 보조 인덱스에 PK가 포함되므로 전체 인덱스 크기가 커진다.
짧고 고유하며, 변경되지 않는 PK를 선호하는 이유다.
-- 나쁜 예: VARCHAR(100)을 PK로 사용
CREATE TABLE users (
email VARCHAR(100) PRIMARY KEY, -- 모든 인덱스에 100바이트 추가
name VARCHAR(50)
);
-- 좋은 예: AUTO_INCREMENT를 PK로 사용
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY, -- 8바이트만 추가
email VARCHAR(100) UNIQUE,
name VARCHAR(50)
);
선택도(Selectivity): 전체 행 대비 고유 값의 비율
-- 나쁜 예: 선택도가 낮은 컬럼
CREATE INDEX idx_gender ON users(gender); -- 'M', 'F' 2개 값만 존재
-- 좋은 예: 선택도가 높은 컬럼
CREATE INDEX idx_email ON users(email); -- 거의 모든 값이 고유함
커버링 인덱스는 쿼리에 필요한 모든 컬럼을 인덱스에 포함시켜, 테이블에 직접 접근하지 않고 인덱스만으로 결과를 반환하는 기법이다.
-- 인덱스 생성
CREATE INDEX idx_user_name_age ON users(name, age);
-- 커버링 인덱스 활용 (Using Index)
SELECT name, age FROM users WHERE name = 'Kim';
-- → 인덱스만 읽고 테이블 접근 없음
-- 커버링되지 않는 경우
SELECT name, age, address FROM users WHERE name = 'Kim';
-- → address는 인덱스에 없으므로 테이블 랜덤 액세스 발생
실행 계획에서 "Using Index"가 표시되면 커버링 인덱스가 적용된 것이다.
특히 JOIN에 쓰이는 FK 컬럼은 반드시 인덱스가 필요하다.
-- orders 테이블의 user_id에 인덱스가 없으면 JOIN 성능 저하
SELECT u.name, o.order_date
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active';
-- FK 컬럼에 인덱스 생성
CREATE INDEX idx_orders_user_id ON orders(user_id);
Cluster Index와 Non-Cluster Index는 단순한 인덱스의 종류가 아니라,
테이블의 저장 방식과 성능 전체에 큰 영향을 주는 핵심 구조다.
인덱스 설계는 결국 트레이드오프다. 조회 성능을 높이면 쓰기 성능이 떨어지고, 인덱스를 많이 만들면 저장 공간과 유지보수 비용이 증가한다. 실제 서비스의 쿼리 패턴을 분석하고, 실행 계획을 확인하며 최적의 지점을 찾아가는 것이 데이터베이스 튜닝의 핵심이다.