쿼리는 인덱스를 잘 타는데도 응답이 들쭉날쭉하고, 특정 시간대만 느려진다면 메모리 캐시가 부족한 신호일 수 있습니다. InnoDB의 버퍼풀(buffer pool) 은 테이블과 인덱스 데이터를 메모리에 올려두는 캐시입니다. 자주 쓰는 데이터가 버퍼풀에 있으면 디스크를 건드리지 않고 메모리에서 바로 응답하므로, 버퍼풀이 작으면 같은 쿼리라도 디스크 I/O가 늘어 느려집니다.
핵심 지표 두 가지
| 지표 | 의미 | 좋은 상태 |
|---|---|---|
| 버퍼풀 크기 | 캐시로 쓸 메모리 총량 | 워킹셋(자주 쓰는 데이터)이 다 들어갈 만큼 |
| 버퍼풀 히트율 | 읽기 요청 중 메모리에서 처리된 비율 | 99% 이상 권장 |
히트율이 낮으면 요청이 자꾸 디스크로 떨어진다는 뜻입니다. 먼저 현재 상태를 봅니다.
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
Innodb_buffer_pool_reads(디스크에서 읽은 횟수)가 Innodb_buffer_pool_read_requests(전체 읽기 요청) 대비 많으면 히트율이 낮은 것입니다. 히트율은 대략 (1 - reads / read_requests) * 100으로 계산합니다.
적정 크기 산정
전용 DB 서버라면 물리 메모리의 50~75% 가 일반적 출발점입니다. OS와 커넥션 버퍼, 정렬 버퍼가 쓸 메모리를 남겨야 하므로 100%를 주면 안 됩니다.
| 서버 메모리 | 권장 버퍼풀 | 비고 |
|---|---|---|
| 8GB | 4~5GB | 소규모, OS 여유 확보 |
| 32GB | 20~24GB | 전용 DB 기준 |
| 128GB | 90~100GB | 워킹셋이 더 작으면 줄여도 됨 |
데이터 전체가 메모리보다 작다면 데이터 크기 + 여유만 주면 충분합니다. 무조건 크게 잡는 게 아니라 "자주 접근하는 데이터가 다 들어가는가"가 기준입니다.
진단과 적용 순서
-
히트율 확인 — 위 STATUS 값으로 계산. 99% 미만이면 크기 부족을 의심합니다.
-
워킹셋 추정 — 자주 쓰이는 테이블·인덱스 크기를 더합니다.
SELECT table_name,
ROUND((data_length + index_length) / 1024 / 1024) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'shop'
ORDER BY size_mb DESC;
- 크기 조정 — MySQL 8.0은 온라인으로 변경 가능합니다(재시작 불필요).
SET GLOBAL innodb_buffer_pool_size = 24 * 1024 * 1024 * 1024; -- 24GB
영구 적용은 설정 파일에 함께 기록합니다.
# /etc/mysql/my.cnf
[mysqld]
innodb_buffer_pool_size = 24G
innodb_buffer_pool_instances = 8
버퍼풀이 1GB를 넘으면 innodb_buffer_pool_instances로 분할해 잠금 경합을 줄입니다.
요점 정리
- 버퍼풀은 데이터·인덱스 메모리 캐시. 작으면 디스크 I/O가 늘어 느려진다.
- 히트율 99% 이상을 목표로 하고,
Innodb_buffer_pool_reads비율로 진단한다. - 전용 서버는 메모리의 50~75%가 출발점. 워킹셋이 다 들어가는지가 기준이다.
- MySQL 8.0은 온라인 변경이 가능하지만 설정 파일에도 영구 기록한다.
버퍼풀 크기를 바꿔가며 히트율과 응답 변화를 직접 측정하는 실습은 데이터베이스 트랙에서 회원가입 없이 무료로 할 수 있습니다.