개요
지금까지 클러스터링 인덱스(Clustering Index)는 테이블의 데이터가 디스크에 물리적으로 저장되는 순서, 정렬을 담당하는 인덱스라고 생각했다.
[Real MySQL 8.0] 에서는 “물리적으로 정렬하여 저장한다.” 라는 문구가 존재했기에 오해가 생겼던 것 같다. 추가적으로 지금까지 멘토링, 면접을 진행하며 아무런 태클을 받지 못했기에 잘못된 지식이 굳어진 것 같다.
오해가 생긴 정확한 이유는 클러스터링 인덱스를 사용하면 테이블의 데이터가
‘단순 배열처럼 연속된 디스크 블록에 정렬되어 저장되는 구조가 된다’ 라고 생각했기 때문이다.
실제로는 B+Tree라는 자료구조를 사용하여 “논리적으로 정렬된 형태”로 저장된다.
이번에는 클러스터링 인덱스에 대해 잘못알고 있었던 지식을 재정리 해보려 한다.
해당 포스팅의 모든 내용은 MySQL 8.0 InnoDB 엔진을 기준으로 한다.
Clustering Index?
클러스터링 인덱스(클러스터드 인덱스; Clustered Index)란
사전적인 의미에서 Clustered
(군집화된) + Index
, 군집화된 인덱스이다.
Each InnoDB table has a special index called the clustered index that stores row data.
MySQL 8.0 InnoDB 엔진의 공식문서에 따르면 InnoDB 테이블에는 테이블 마다 1개씩 ‘클러스터형 인덱스’라 불리는 특별한 인덱스가 존재하며, 이 인덱스는 실제 행(row)를 저장한다고 한다.
즉, 클러스터링 인덱스를 한마디로 정의히면, 테이블의 전체 행을 저장하고 있는 정렬된 거대한 인덱스(테이블 구조와 동일한)라고 생각하면 된다.
해당 인덱스는 B+ Tree 구조로 디스크에 페이지 단위로 저장되며, 리프 노드에는 실제 테이블의 row 데이터 전체를 저장한다. 즉, 저장된 데이터 관점에서의 테이블 그 자체이다.
정렬 기준
데이터를 정렬해서 저장하기 위해서는 정렬의 기준이 필요하다.
InnoDB에서는 아래와 같은 정렬 기준과 우선순위를 가진다.
When you define a PRIMARY KEY on a table, InnoDB uses it as the clustered index.
일반적으로 테이블에 정의된 PK를 기준으로 정렬된다.
If you do not define a PRIMARY KEY for a table, InnoDB uses the first UNIQUE index with all key columns defined as NOT NULL as the clustered index.
If a table has no PRIMARY KEY or suitable UNIQUE index, InnoDB generates a hidden clustered index named GEN_CLUST_INDEX on a synthetic column that contains row ID values. The rows are ordered by the row ID that InnoDB assigns.
PK가 정의되지 않은 테이블의 경우, 모든 키 컬럼이 NOT NULL
로 정의된 UNIQUE
인덱스를 기준으로 정렬된다.
UNIQUE
인덱스도 존재하지 않는 경우, GEN_CLUST_INDEX
라는 이름의 숨겨진 컬럼을 기준으로 정렬되며 해당 인덱스는 row ID 값을 포함한 합성 컬럼이라고 한다.
클러스터링 인덱스로 지정되는 컬럼의 우선순위는 아래와 같다.
- PK 기준
- NOT NULL UNIQUE 인덱스 기준
- 내부적으로 생성한 인덱스 기준
Secondery Index
How Secondary Indexes Relate to the Clustered Index
Indexes other than the clustered index are known as secondary indexes. In InnoDB, each record in a secondary index contains the primary key columns for the row, as well as the columns specified for the secondary index. InnoDB uses this primary key value to search for the row in the clustered index.
InnoDB에서 클러스터링 인덱스를 제외한 모든 인덱스는 세컨더리 인덱스라 불린다.
세컨더리 인덱스는 인덱스로 정의된 컬럼
+ 클러스터링 인덱스의 컬럼 값(이하 PK
)을 포함한다.
모든 세컨더리 인덱스는 PK를 포함한다. 따라서 PK 값이 길면 세컨더리 인덱스가 차지하는 공간이 커지므로, 기본 키는 짧게 구성하는 것이 유리하다고 한다.
또한, InnoDB에서 보조 인덱스를 통해 특정 행을 조회하는 경우, 결국에는 보조 인덱스(Secondary Index)의 리프 노드에 저장된 PK 값을 이용해,클러스터링 인덱스(Clustered Index)에서 해당 행의 실제 데이터를 조회하게 된다.
사용 이유 (vs Non-Clustered Index)
그렇다면 Clustered Index
의 구조를 사용하는 이유는 뭘까?
대부분 클러스터링 인덱스의 장점은 빠른 읽기이며, 단점은 느린 쓰기이다. 일반적으로 웹 서비스와 같은 온라인 트랜잭션 환경에서는 쓰기와 읽기 비율이 2:8 혹은 1:9 정도이기에 조금 느린 쓰기를 감수하고 읽기를 빠르게 유지하는 것은 매우 중요하다.
- Real MySQL 8.0 1
해당 구조를 사용하지 않는 Non-Clustered Index
와 비교하여 알아보자.
Non-Clustered Index
Non-Clustered Index는 테이블의 실제 데이터와 인덱스가 분리되어 저장되는 인덱스 구조이다.
즉, Inno DB의 세컨더리 인덱스의 구조라고 생각하면 된다.
Clustered Index를 지원하지 않고 Non-Clustered Index만 지원하는 DB로는 Oracle
, PostgreSQL
, MySQL(MyISAM)
등이 있다.
Non-Clustered Index는 인덱스를 통해 조회하고자하는 데이터의 PK 혹은 포인터를 조회하고 다시 테이블에서 실제 데이터를 조회하는 Double Lookup
방식으로 데이터를 저장한다.
Clustered vs Non-Clustered
클러스터링 인덱스는 PK기반 조회시 성능을 보장하기 위해 사용된다.
다만, PK가 변경될 경우 무거운 데이터의 재배치가 이루어지기에 성능이 저하된다.
빠른 PK 기준의 조회와 범위 쿼리가 중요한 경우 → 클러스터링 인덱스 중심의 설계
다양한 조건 검색의 최적화가 필요한 경우 → 논 클러스터링 인덱스를 병행 사용
클러스터링 인덱스 (Clustered Index)
항목 | 내용 |
---|---|
장점 | 🔸 PK 기반 조회가 매우 빠름 → 인덱스 탐색만으로 row 전체 바로 조회 🔸 범위 검색에 최적 → 리프 노드 순차 접근 🔸 디스크 접근 최소화 → I/O 효율적 🔸 인덱스 = 테이블 → 구조 간결 |
단점 | 🔸 PK가 변경되면 성능 저하 → 데이터 재배치 필요 🔸 삽입/삭제 시 B+ Tree 구조 유지를 위한 오버헤드 발생 |
논 클러스터링 인덱스 (Non-clustered Index)
항목 | 내용 |
---|---|
장점 | 🔸 여러 개 생성 가능 → 다양한 조건 최적화 🔸 테이블 정렬에 영향 없음 🔸 복합 인덱스 조합 등 다양한 검색 패턴 지원 |
단점 | 🔸 Double Lookup 발생 → 보조 인덱스로 PK or row pointer 찾고 다시 테이블 접근 🔸 인덱스 + PK 저장으로 디스크 사용량 증가 🔸 PK가 길면 인덱스도 커짐 (InnoDB) |
결론
MySQL 8.0 InnoDB 에서 클러스터링 인덱스는 테이블 그 자체이다.
InnoDB의 클러스터링 인덱스는 데이터를 PK(혹은 다른 기준)순서에 따라 정렬된 구조로 저장한다.
다만, 배열과 같은 형태로 연속된 디스크 블록에 정렬하는 것은 아니고 B+Tree라는 자료구조를 사용하여 “논리적으로 정렬된 형태”로 저장된다.
세컨더리 인덱스(보조 인덱스)는 인덱스의 기준이 되는 컬럼과 PK를 포함하고 있으며, 실제 행 조회 시 클러스터링 인덱스를 통해 조회하게 된다.
클러스터링 인덱스는 PK기반 조회시 성능을 보장하기 위해 사용된다.
다만, PK가 변경될 경우 무거운 데이터의 재배치가 이루어지기에 성능이 저하된다.
빠른 PK 기준의 조회와 범위 쿼리가 중요한 경우 → 클러스터링 인덱스 중심의 설계
다양한 조건 검색의 최적화가 필요한 경우 → 논 클러스터링 인덱스를 병행 사용
Reference
- https://dev.mysql.com/doc/refman/8.4/en/innodb-index-types.html
- Real MySQL 8.0 1
'의문과 실험' 카테고리의 다른 글
회원 테이블의 PK를 Long 타입에 매핑하는 이유 (0) | 2024.02.04 |
---|---|
제네릭은 왜 Lower Bounded를 지원하지 않을까? 와일드카드의 사용처는? (1) | 2024.01.09 |
메인 메서드에 대한 고찰 (0) | 2024.01.03 |
Monitor와 Synchronized 동작 알아보기 (1) | 2024.01.01 |
상속 시, 오버라이딩된 메서드의 접근제어자는 왜 확장만을 허용할까 (0) | 2023.12.19 |