리마큐를 읽다가 아주 신기한 사실을 알게 되어서, 이에 대해서 글을 남겨보고자 합니다.
거대한 개념은 아니라서, 글은 굉장히 짧을 예정이네요!
클러스터링이란 여러 개를 하나로 묶는다는 의미를 지닙니다.
클러스터링 인덱스란, InnoDB 스토리지 엔진에서만 지원하는 인덱스에요!
도대체 이게 무엇이며, 왜 지원하는 것일까요?
클러스터링 인덱스는 테이블의 프라이머리 키에 대해서만 적용되는 내용이에요!
즉, 프라이머리 키 값이 비슷한 레코드끼리 묶어서 저장하는 것을 클러스터링 인덱스라고 표현하는 것이에요.
이게 무엇인지 그림을 통해서 살펴볼까요?
출처 : 리마큐 1권
리프노드에 실제 레코드의 값들이 저장되어 있는 것을 볼 수 있어요.
또한, 프라이머리 키로 정렬이 되어있고, 또한 비슷한 것들끼리 묶여있죠!
이로 인해서, 프라이머리 키로 검색할 때면 인덱스를 굉장히 효율적으로 사용할 수 있어요.
보통, 조건을 통해서 검색의 범위를 줄이는 것이 가장 효율적이며, 이를 '작업 범위 결정 조건' 이라고 해요.
클러스터링 인덱스를 활용하게 되면, 검색 조건을 '작업 범위 결정 조건' 으로 활용하는 것이 굉장히 쉬워진다는 것이 특징이죠.
또한, 물리적으로 저장되어 있는 위치도 위와 동일하게 되요.
물리적으로 저장되어 있는 위치가 결정되어 있으면 어떤 것들이 좋을까요?
출처 : 리마큐 1권
위 그림은 순차 I/O 와 랜덤 I/O 를 그림으로 표현한 것이에요.
딱봐도, 순차 I/O 가 훨씬 읽는 속도가 빠를 것 같지 않나요?
맞아요.
이는, 디스크의 물리적인 구조가 영향을 끼치게 돼요.
간단하게 디스크는 원판과, 헤더가 존재해요!
순차 I/O 는 헤더를 가만히두고 원판을 돌리면서 읽으면 되는 반면에, 랜덤 I/O 와 같은 경우는 헤더를 움직여가면서 데이터를 읽어야 하죠.
물리적으로 헤더를 움직여야하니 당연히 엄청 느리지 않을까요?
그렇다면 SSD 를 쓰면 되지 않냐구요?
근데, 실제로 SSD 도 순차 I/O 와 랜덤 I/O 의 속도차이가 꽤 난답니다.
그 이유는 나도 몰라영!
세컨더리 인덱스는 프라이머리 키로 구성된 인덱스가 아닌 인덱스를 의미합니다.
아마, 인덱스에 대해 공부해보신 분은 아시겠지만, 세컨더리 인덱스는 프라이머리 키를 저장하고 있습니다.
도대체 왜 프라이머리 키를 저장하고 있을까요?
그냥 바로 레코드를 가르키고 있으면 되지 않나요?
그 이유는 클러스터링 인덱스에 있었습니다.
클러스터링 인덱스는 데이터가 변경되면 실제로 물리적인 저장 위치도 바꾸게 돼요.
이를 표현한 그림은 아래와 같습니다.
출처 : 리마큐 1권
emp_no 가 프라이머리 키이고, 10007번을 10002 번으로 바꾼다고 했을 때, 인덱스의 구조는 위와 같이 변경되고 데이터의 물리적인 저장도 실제로 변경하게 됩니다!
세컨더리 인덱스가 실제 레코드의 위치를 가르키고 있었다면, 이 부분에서 문제가 발생하지 않을까요?
그렇다면, 실제로 데이터의 변경이 일어날 때마다, 세컨더리 인덱스도 변경하면 되지 않냐구요?
그렇게 한다고 했을 때, 하나의 테이블에 인덱스가 많아지면 어떻게 될까요?
부하가 너무 커지지 않을까요?
그렇기 때문에 이러한 방법을 선택한 것입니다.
지금까지 설명한 것들로 인해서, 세컨더리 인덱스를 통해 검색을 진행하게 되면, 인덱스를 두번 타게 됩니다.
일단, 세컨더리 인덱스를 통해서 프라이머리 키를 찾고, 프라이머리 키를 통해 검색을 진행하면서 클러스터링 인덱스를 활용하는 것이죠.
굉장히 성능 저하가 클 것 같지만, 생각보다 크지 않다고 합니다.
장점은 지금까지 설명한 부분들이 장점입니다.
아무래도, 너무 신기하고 멋져서 적은 글이기 때문에 신나서 좋은 점만 적었네요 허허허
아! 조금 더 생각해보니까, 세컨더리 인덱스를 통해서 검색을 진행하게되더라도 결국 클러스터링 인덱스를 통해 검색하기 때문에 커버링 인덱스를 활용할 수 있다는 것도 장점이네요.
프라이머리 키의 값이 커지면, 테이블에 존재하는 모든 세컨더리 인덱스의 크기가 커진다는 치명적인 단점이 존재합니다.
아무래도, 세컨더리 인덱스의 리프노드에는 모두 프라이머리 키 값이 들어가 있으니까요.
또한, 쓰기 연산이 느려집니다.
실제로 물리적인 저장 위치를 바꿔야 하니까요, 하지만, InnoDB 에서는 쓰기 지연을 활용하여 이를 최적화 하고 있습니다.
마지막으로, 세컨더리 인덱스를 활용한 검색을 진행할 경우, 검색을 두 번 진행하게 됩니다.
성능 저하는 미미하다고 하였지만, 저하가 발생하기는 하니 단점이라고 할 수 있겠네요!