클러스터링이란 여러 개를 하나로 묶는다
는 의미로 주로 사용된다.
MySQL의 클러스터링은 테이블의 레코드를 비슷한 것(프라이머리 키를 기준으로)들끼리 묶어서 저장하는 형태로 구현
→ 주로 비슷한 값들을 동시에 조회하는 경우가 많다는 점에 착안한 것이다.
MySQL의 클러스터링 인덱스는 InnoDB 스토리지 엔진
에서만 지원하며, 나머지 스토리지 엔진에서는 지원되지 않는다.
1. Clustering Index
- 클러스터링 인덱스는 PK에 대해서만 적용되는 내용이다.
- PK 값이 비슷한 레코드끼리 묶어서 저장하는 것을 클러스터링 인덱스라고 표현한다.
PK 값에 의해 레코드의 저장 위치가 결정된다.
PK 값이 변경되면, 레코드의 저장 위치도 변경되어야 한다.
- 클러스터링 인덱스는 인덱스 알고리즘이라기보다 테이블 레코드의 저장 방식이라고 볼 수 있다.
- InnoDB와 같이 항상 클러스터링 인덱스로 저장되는 테이블은 PK 기반의 검색이 매우 빠르며, 대신 레코드의 저장이나 PK의 변경이 상대적으로 느리다.
클러스터링 인덱스의 리프 노드에는 레코드의 모든 컬럼이 같이 저장되어 있다.
- 클러스터링 테이블은 그 자체가 하나의 거대한 인덱스 구조로 관리된다.
PK가 없는 InnoDB 테이블의 클러스터링 구성 과정
- PK가 있으면 기본적으로 PK를 클러스터링 키로 선택
- NOT NULL 옵션의 유니크 인덱스 중 첫 번째 인덱스를 클러스터링 키로 선택
- 자동으로 유니크한 값을 가지도록 증가되는 컬럼을 내부적으로 추가한 후, 클러스터링 키로 선택
내부적으로 생성된 레코드의 일련번호 컬럼은 사용자에게 노출되지 않으며, 쿼리 문장에 사용할 수 없다.
2. 세컨더리 인덱스에 미치는 영향
- MyISAM이나 MEMORY 테이블 같은 클러스터링 되지 않은 테이블은 INSERT될 떄 처음 저장된 공간에서 절대 이동하지 않는다.
- 레코드가 저장된 주소는 ROWID 역할을 한다.
만약 InnoDB 테이블의 세컨더리 Index가 실제 레코드가 저장된 주소를 가지고 있다면?
- 클러스터링 키 값이 변경될 때마다 레코드의 주소가 변경되고, 그때마다 해당 테이블의 모든 인덱스에 저장된 주솟값을 변경해야 한다.
- 이런 오버헤드를 제거하기 위해 클러스터링 테이블의 모든 세컨더리 인덱스는 해당 레코드가 저장된 주소가 아니라 PK를 저장하도록 구현되어 있다.
예시
mysql > CREATE TABLE employyes (
emp_no INT NOT NULL,
first_name VARCHAR(20) NOT NULL,
PRIMARY KEY (emp_no),
INDEX ix_firstname (first_name)
);
mysql > SELECT * FROM employees WHERE first_name='Aamer';
- MyISAM : ix_firstname 인덱스를 검색해서 레코드의 주소를 확인 후, 이를 이용해 최종 레코드를 가져옴
- InnoDB : ix_firstname 인덱스를 검색해 PK를 확인 후, PK Index를 검색해서 최종 레코드를 가져옴
3. 장단점
장점
- PK로 검색할 때 처리 성능이 매우 빠름 ( 특히, PK의 범위 검색)
- Table의 모든 세컨더리 인덱스가 클러스터링 키를 갖기 때문에 인덱스만으로 처리될 수 있는 경우가 많음(커버링 인덱스)
단점
- Table의 모든 세컨더리 인덱스가 클러스터링 키를 갖기 때문에 클러스터링 키의 크기가 클 경우 전체적으로 인덱스의 크기가 커
- 세컨더리 인덱스를 통해 검색할 때 PK로 다시 한번 검색해야 하므로 처리 성능이 느림
- INSERT할 때 PK에 의해 레코드의 저장 위치가 결정되기 때문에 처리 성능이 느림
- PK를 변경할 때 레코드를 DELETE하고 INSERT하는 작업이 필요하기 때문에 처리 성능이 느림
결론
- 클러스터링 인덱스는 빠른 읽기, 느린 쓰기
- 웹 서비스와 같은 온라인 트랜잭션 환경에서는 쓰기와 읽기의 비율이
2:8 or 1:9
이기 떄문에 조금 느린 쓰기를 감수하고 읽기를 빠르게 유지하는 것은 매우 중요하다.
RealMySQL 8.0