[MySQL8.0] B-Tree 인덱스 사용에 영향을 미치는 요소

2022. 6. 17. 15:13데이터베이스

반응형

이 글은 'Real MySQL 8.0 개발자와 DBA를 위한 MySQL 실전 가이드'를 보고 학습한 내용을 정리한 글입니다.

 


 

B-Tree 인덱스는 인덱스를 구성하는

1. 칼럼의 크기와

2. 레코드의 건수

3. 유니크한 인덱스 키 값의 개수

등에 의해 작업 성능 영향을 받습니다.

 

 InnoDB 스토리지 엔진에서, 주기억장치(하드디스크)에 데이터를 저장하는 가장 기본적인 단위를 페이지, 블록이라고 합니다. 이론적으로 디스크의 모든 읽기와 쓰기는 페이지 단위 미만이 될 수 없습니다.

 또, 페이지는 InnoDB 스토리지 엔진의 버퍼 풀에서 데이터를 버퍼링(캐싱) 하는 기본 단위입니다. 인덱스 구조에서 루트, 브랜치, 리프 노드를 구분하는 기준이 바로 이 페이지 단위입니다.

 

 흔히 오해하기 쉬운 것이, B-Tree가 Binary의 B를 의미하고 있다는 오해입니다. 물론 내부구조를 이진트리로 구성해도 작동은 되겠지만, 노드당 자식을 최대 2개만 갖게 되어 트리의 depth가 너무 깊어지는 현상이 일어나게 됩니다. 즉, 디스크 랜덤 I/O가 비정상적으로 늘어나는 결과를 초래하게 됩니다. 성능하락도 당연합니다.

 결론적으로 B-Tree의 B는 Balanced를 의미합니다. https://ko.wikipedia.org/wiki/%EC%9E%90%EA%B0%80_%EA%B7%A0%ED%98%95_%EC%9D%B4%EC%A7%84_%ED%83%90%EC%83%89_%ED%8A%B8%EB%A6%AC 에 따르면, B-Tree는 삽입과 삭제 연산에서 자동으로 트리의 depth를 최소화하여 유지하는 트리라고 합니다. 2개를 초과하는 자식노드를 가질 수도 있고, 어느 한 쪽으로 쏠리는 트리의 모양을 가지지도 않아서 최악의 경우에도 이진 트리보다 훨씬 좋은 성능을 보입니다.

 


 

 그런데, 이진 트리보다 성능이 좋다고 해서 무작정 써도 되는 것은 아닙니다. 

 

# 인덱스를 구성하는 칼럼의 크기

 B-Tree는 한 페이지에 몇 개의 노드를 저장할 수 있을까요? 이진트리의 2개보다는 많을 것 같다는 예상이 듭니다.

최악의 경우를 따져보겠습니다. 페이지의 크기를 InnoDB의 기본값인 16KB라고 가정하고, 인덱스의 키 크기는 페이지의 최대 크기에 비례하기 때문에 가장 큰 길이의 인덱스 크기는 페이지가 16KB인 경우에 3072B 입니다. 각 노드는 자식노드의 주소를 K-V 형태로 갖고 있습니다. 자식노드의 주소의 크기 값을 12B라고 가정한다면 각 노드는 3084입니다.

 

페이지의 구조. 노드당 780B를 차지한다

 

 결론적으로 각 페이지는 최악의 경우 16384 / 3084 = 5.31258106355 개의 노드를 가질 수 있게 됩니다. 여전히 이진트리보다는 많은 노드를 포함하지만 tree의 depth가 너무 높아져서 성능은 정말 나쁠 것 같네요. 이 최악의 경우를 교훈삼아 인덱스를 구성하는 칼럼의 크기를 적당히 작은 크기로 유지하는 것이 성능상에 이점이 많을 것이라 생각합니다.

 

 

 그렇다면, 최선의 경우에 페이지는 몇 개의 노드를 포함할 수 있을까요?

동일한 16KB 페이지에서, 레코드의 키 타입을 int로 지정하면 각 노드는 16B만을 차지하게 됩니다

페이지의 구조, 노드당 16B를 차지하는 이상적인 그림이다.

 

 이 최선의 경우에는 16384 / 16 = 1024 개의 노드를 저장할 수 있습니다. 페이지의 크기가 더 커진다면 격차는 더 커질 것입니다. 단순 비교를 해봐도 약 200배의 공간 효율성을 가집니다. B-Tree의 depth도 획기적으로 줄게 됩니다.
반응형