본문 바로가기
허브 살리기 프로젝트

인덱스와 버퍼 풀

by jay-choe 2024. 1. 25.

 

인덱스에 관해서 정리하다보면

 

문득 인덱스도 결국 디스크상에 존재하는 것이고

브랜치 노드를 탐색하는 과정에서 계속 Disk I/O가 있으며

 

탐색 과정은 루트 노드에서 탐색 과정을 진행 할 때 마다

Disk I/O로 접근해서 다음 노드의 주소를 가져와야 하기 때문에

 

인덱스 스캔도 생각보다 비효율적일지 않을까?라는 의문에서

생각을 정리하고 이해한 내용을 바탕으로 정리했다.

 

개발에서 사용하게 될 인덱스는

거의 B-Tree (Balanced Tree) 구조이므로

 

물론  B+Tree 인덱스도 사용된다고 하지만 편의상 B-Tree 인덱스로 확인하려고 하며

데이터베이스는 MySQL기준으로 확인하였다.

 

B-Tree 인덱스의 구조 (RealMySQL 8.0 그림 8.4)

 

그림에서 나오는 개념을 간략히 정리하면.

 

페이지란 디스크와 메모리에 읽고 쓰는 기본 단위이다.

 

데이터베이스 시스템에 따라 다를 수 있으며, 일반적으로 4KB, 8KB, 16KB 등과 같이 고정된 크기를 갖는다.

MySQL에서는 페이지의 기본 크기가 16KB라고 한다.

 

루트 노드는 처음 접근하게 되는 데이터이며 트리 구조에 맞게 여러 브랜치 노드(중간 중간 효율적인 탐색을 위해)를 거쳐서 결국 마지막 리프 노드로 접근하게 된다.

 

이 글에서 확인하고자 하는 것은 탐색 알고리즘은 아니기 때문에 해당 탐색 알고리즘 관련 내용은 생략한다.

 

위 그림은 처음에 접근하게 되는 데이터가 있고 해당 데이터들을 탐색 후 특정 범위에 따라

 

중간 지점에서 만족하는 조건을 계속 찾으면서

마지막에 도달하면 실제 데이터 파일에서의 위치가 나타난다는 것을 보여준다.

 

마지막에 도달해서

만족하는 결과가 있으면 그에 맞는 페이지를 가져온다. (Disk I/O)

 

여기서 들게되는 생각은 서론처럼 결국 인덱스의 페이지에 접근하는 것도 Disk I/O이기 때문에

 

매번 인덱스 탐색을 위해

인덱스 페이지를 가져오는 I/O를 당연히 하지 않을 것이라는 생각이다.

 

Disk I/O는 메모리 접근에 비해 상대적으로 시간이 많이 드는 작업이기 때문이다.

 

이런 비효율적인 I/O를 줄이기 위해 캐싱을 사용하며 메모리에 버퍼 풀이라는 공간이 존재한다.

 

버퍼 풀은 메인 메모리 내에서 데이터와 인덱스 데이터가 디스크에 접근될 때

해당 데이터를 캐시하는 영역이다.

 

버퍼 풀을 통해서 자주 접근되는 데이터를

메모리에서 디스크 접근 없이 바로 가져올 수 있다.

 

MySQL을 위한 서버에서는 메모리의 최대 80%까지를 InnoDB의 버퍼 풀로 할당하여 사용하는 경우가 많다고 한다.

 

대량의 읽기 요청을 효율적으로 처리하기 위해

버퍼 풀은 데이터를 페이지 단위로 나누어 관리하며

한 페이지에는 여러 로우 (row)가 속할 수 있다.

 

버퍼풀에 존재하는 데이터는 LRU 알고리즘에 따라

잘 접근되지 않는 데이터 페이지는 캐시에서 제거하는 방식으로 버퍼풀을 관리한다.

 

그래서 버퍼풀의 사이즈가 크면 결국 Disk I/O 횟수를 줄일 수 있고

작다면 교체하는 주기가 빈번하여 성능이 감소 할 것이다.

 

결국 데이터베이스에서 사용하는 물리 메모리의 크기가 크면 버퍼풀 사이즈를 크게 할당 할 수 있고

이는 성능 향상에 영향을 미친다는 것을 확인 할 수 있다.

 

 

참고: https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html