MySQL 서버에서 클러스터링은, 테이블의 레코드를 PK를 기준으로 비슷한 값들로 묶어서 저장하는 형태로 구현된다. 클러스터링 인덱스는 오직 InnoDB 엔진에서만 지원한다.

클러스터링 인덱스

이 인덱스는 테이블의 PK에 대해서만 적용되는 내용이다. 위에서도 언급했지만, PK가 비슷한 레코드끼리 묶어서 저장하는걸 클러스터링 인덱스라고 표현한다. 중요한건 PK 값에 의해서 레코드의 저장위치가 결정된다는 사실이다. 자연히 PK가 변하면 레코드의 물리적인 저장위치까지 바뀐다. 이렇듯 클러스터링된 테이블은 PK에 대한 의존도가 상당히 크기 때문에 PK는 신중히 결정해야 한다.

PK에 의해 클러스터링 되므로, 클러스터링 인덱스(클러스터링 테이블)을 논하는 맥락에서는 PK를 클러스터링 키라고도 한다.

InnoDB처럼 항상 클러스터링 인덱스로 저장되는 테이블은 PK기반의 검색이 매우 빠른 대신, 레코드의 저장이나 PK의 변경이 상대적으로 느린 속성이 있다.

한편 B-Tree 인덱스도 인덱스 키 값으로 이미 정렬되어 저장된다. 그럼에도 B-Tree 인덱스는 클러스터링 인덱스라고 하지 않음. 오직 PK값으로 정렬되어 저장된 경우에만 클러스터링 인덱스라고 라고 한다.

image.png

위 그림을 보면 구조 자체는 B-tree와 비슷하다. 하지만 B-Tree의 리프노드는 오직 보조키를 위한 것이었지만 클러스터링 인덱스의 리프에는 레코드의 모든 칼럼이 저장되어있다.

그렇다면 PK가 없는 InnoDB 테이블은 어떻게 클러스터링 테이블로 구성될까? InnoDB는 다음 우선순위대로 PK를 대신할 칼럼을 선택한다.

  1. NOT NULL 옵션의 유니크 인덱스중 첫 번째 인덱스를 클러스터링 키로 선택한다.
  2. 그것도 없으면 자동으로 유니크한 값을 가지도록 증가하는 컬럼을 내부적으로 추가한 후 클러스터링 키로 사용한다.

2번처럼 생성된 키는 사용자가 전혀 사용할 수 없다. InnoDB테이블에서 클러스터링 인덱스는 테이블당 오직 하나만 가질 수 있는 혜택이므로, 가능하다면 직접 생성해서 사용하자.

보조키에 미치는 역할

그렇다면 PK는 보조키(세컨더리 인덱스)에 어떤 영향을 미치는가?

InnoDB가 아닌, MyISAM이나 MEMORY테이블같이 클러스터링 되지 않는 테이블은 레코드가 처음 한번 INSERT된 공간에서 절대 이동하지 않는다. 그리고 저장된 공간에 대한 주소는 내부적인 레코드 아이디(ROW ID)역할을 한다. 그리고 PK나 보조키는 ROW ID를 이용해 실제 레코드의 데이터를 찾아오므로, PK나 보조키가 사실 별 차이가 없다.

반면 InnoDB의 클러스터링 테이블의 모든 세컨더리 인덱스(보조키)는 해당 레코드가 저장된 주소가 아니라, 오직 프라이머리 키 값을 저장하도록 구현되어있다.