클러스터링 인덱스

saewoohan·2025년 3월 13일

MySQL

목록 보기
5/9
post-thumbnail

MySQL InnoDB 스토리지 엔진은 클러스터링 인덱스구조를 사용하여 데이터를 저장한다. 이때, 클러스터링이란 여러 개를 하나로 묶는다는 의미로 사용되는데. 즉, MySQL서버에서 클러스터링은 테이블의 레코드를 비슷한 것 끼리 묶어서 저장하는 형태로 구현되는데 비슷한 값을 동시에 조회하는 일이 많다는 것에 착안한 것이다.


클러스터링 인덱스

클러스터링 인덱스는 데이터 자체를 정렬된 구조로 저장하는 인덱스이다. MySQL에서는 테이블의 PK가 클러스터링 인덱스로 적용되며, 중요한 점은 PK 값에 의해 레코드의 실제 저장 위치가 결정된다는 것이다. 이와 같은 특징 때문에 엄밀하게 따지면 클러스터링 인덱스는 테이블 레코드의 저장방식이라고도 볼 수 있다.

PK로 인해 저장 위치가 결정된다는 것은 결국 PK 값이 변경된다면 레코드의 저장 위치가 바뀌어야 한다는 것이고 PK의 선택이 성능에 중요한 영향을 미친다. 그렇기에 일반적으로 InnoDB와 같이 클러스터링 인덱스로 저장되는 테이블은 PK 기반의 검색이 매우 빠르다. 하지만, 레코드 저장이나 PK의 변경에는 상대적으로 느리다.

💡 PK변경은 비용이 드는 작업

UPDATE test_table SET id=100 WHERE id=200;

만약 위와 같은 쿼리를 통해 PK를 변경하는 문장이 실행되면, 변경된 PK에 맞게 페이지를 이동시켜야할 것이다.

위의 그림처럼 클러스터링 인덱스는 실제로 리프 노드에 레코드의 모든 컬럼이 같이 저장되어 있다. 즉, 클러스터링 테이블은 그 자체로 하나의 거대한 인덱스라고 볼 수 있는 것이다.

PK가 없는 InnoDB 테이블이 존재할 수도 있는데, 이때는 InnoDB 스토리지 엔진은 NOT NULL 옵션의 UNIQUE INDEX가 있다면 해당 인덱스를 클러스터링 키로 선택하고, 이도 없다면 자동으로 유니크 한 값을 가지는 컬럼을 추가한 후 클러스터링 키로 지정한다.

이때, 자동으로 추가된 값은 사용자에게 노출되지 않으며 쿼리 문장에 명시적인 사용이 불가하기에 PK는 꼭 생성하는 것이 좋다.


논 클러스터링 인덱스

MyISAM, MEMORY 같은 클러스터링되지 않은 테이블은 한번 저장된 데이터는 절대 해당 공간에서 움직이지 않는다. 그렇기에 PK나 세컨더리 인덱스는 그 주소를 이용해서 실제 데이터 레코드를 찾아온다. 하지만, InnoDB에서 주소를 가지고 있다면 이는 꽤 문제가 생길 수 있다. 클러스터링 인덱스는 PK 값 순서대로 데이터가 물리적으로 정렬되어 저장되기에, 클러스터링 키 값이 변경될 때마다 데이터 레코드의 주소가 변경되고 그때마다 해당 테이블의 모든 인덱스에 저장된 주소값을 변경시켜줘야 하는 작업이 필요하다.

그러나, PK 값은 변경되지 않으므로, 논 클러스터링 인덱스는 PK 값을 저장하여 주소 값에 영향을 받지 않도록 한다.

CREATE TABLE employees (
    emp_id INT PRIMARY KEY,       -- 클러스터링 인덱스 (PK)
    name VARCHAR(100),
    department VARCHAR(50),
    salary INT,
    INDEX idx_name (name)         -- 논 클러스터링 인덱스
);
SELECT * FROM employees WHERE name = 'John'

위의 쿼리를 실행 시, PK(emp_id)를 찾은 후, 다시 클러스터링 인덱스를 검색하여 실제 데이터를 조회한다.

클러스터링 인덱스 장점과 단점

클러스터링 인덱스를 사용한 테이블과 클러스터링 되지 않은 인덱스를 사용했을 때, 상대적인 장단점을 비교하면 아래와 같다.

장점

  1. PK 기반 검색 성능이 굉장히 뛰어나다.
  2. 데이터가 물리적으로 정렬되어 있어 BETWEEN, ORDER BY, GROUP BY같은 범위 검색 성능이 뛰어나다.

단점

  1. 테이블의 모든 세컨더리 인덱스가 PK를 갖기 때문에, PK 값의 크기에 영향을 받는다.
  2. 세컨더리 인덱스를 통한 검색은 PK를 통한 추가적인 검색을 요구한다.
  3. PK 변경이 비효율적이고 처리 성능이 느리다.
  4. 데이터 삽입 시에 데이터의 저장 위치는 PK에 의해 결정되므로 삽입 성능이 느리다.

이렇게, 클러스터링 인덱스는 빠른 읽기를 제공하지만 쓰기 작업에는 비용이 더 소요되는 것을 알 수 있다. 보통 일반적인 웹 서비스에서는 쓰기와 읽기 비율 중에 읽기 비율이 훨씬 많기 때문에, 읽기를 빠르게 유지하는 것이 중요하다.


클러스터링 인덱스 주의점

클러스터링 인덱스 키의 크기

클러스터링 테이블의 경우에는 모든 세컨더리 인덱스가 PK 값을 포함한다. 그렇기에, PK의 크기가 커지면 세컨더리 인덱스도 자동으로 커진다. 별거 아닐 수 있지만, 테이블에 세컨더리 인덱스가 5개가 생성된다고 하면 인덱스의 크기는 5배씩 차이나는 것이고, 레코드가 많아질수록 이 차이는 더 뚜렷해 질것이다.

PK는 실용적인 컬럼을 선택

일반적으로 PK를 AUTO INCREMENT같은 값을 사용하는 사례도 많지만, InnoDB에서는 PK를 통해서 레코드의 위치가 결정되기 때문에 PK 검색 처리 속도가 굉장히 빠르다. 그렇기에 실용적으로 사용할 수 있는 컬럼이 있다면 해당 컬럼을 PK로 결정하는 것이 좋다.

PK는 반드시 명시

앞서 언급했듯이 MySQL InnoDB에서는 명시적인 PK가 없다면, 내부적으로 숨겨진 컬럼을 추가하여 사용한다.

이때, 해당 컬럼은 직접 컨트롤 할 수 없고 성능상 최적화가 어렵기에 명시적으로 AUTO INCREMENT 컬럼을 추가하여 PK를 설정하는 것이 더 낫다.


참조

Real MySQL 8.0 (1권)
https://blog.ex-em.com/1699
https://medium.com/@genchilu/a-brief-introduction-to-cluster-index-and-secondary-index-in-innodb-9b8874d4da6a

0개의 댓글