MySQL의 버퍼와 캐시는 크게 InnoDB Buffer Pool을 중심으로 동작하며, 다음과 같은 데이터를 메모리에 보관합니다:
활용 방식:
페이지 (Page)
InnoDB는 디스크와 메모리 간 데이터를 페이지라는 16KB 단위로 관리합니다. row 단위가 아닌 페이지 단위로 읽고 쓰는 이유는 디스크 I/O의 효율성 때문입니다.
LRU 알고리즘
Least Recently Used의 약자로, 가장 오래 사용되지 않은 데이터를 먼저 제거하는 캐시 교체 알고리즘입니다. InnoDB는 전통적인 LRU를 개선한 Midpoint Insertion Strategy를 사용합니다.
Dirty Page
메모리에서 수정되었지만 아직 디스크에 기록되지 않은 페이지를 말합니다. 체크포인트 시점이나 Buffer Pool 공간 부족 시 디스크로 플러시됩니다.
MVCC (Multi-Version Concurrency Control)
동시성 제어를 위해 데이터의 여러 버전을 유지하는 기법입니다. Undo 페이지가 이를 위해 사용됩니다.
InnoDB Buffer Pool의 구조적 특징
InnoDB Buffer Pool은 단순한 LRU가 아니라 3가지 영역으로 나뉩니다:
새 페이지는 바로 LRU 리스트의 맨 앞이 아닌 Midpoint(Old 영역의 시작점)에 삽입됩니다. 이후 일정 시간 내에 다시 접근되면 Young 영역으로 승격됩니다. 이는 풀 테이블 스캔 같은 대량 읽기 작업이 Buffer Pool을 오염시키는 것을 방지합니다.
Change Buffer의 활용
세컨더리 인덱스 수정 시, 해당 인덱스 페이지가 Buffer Pool에 없다면 디스크에서 읽어와야 합니다. 이 때 Change Buffer가 변경사항을 임시 저장하고, 나중에 해당 페이지가 로드될 때 한꺼번에 병합(merge)합니다. 이는 랜덤 디스크 I/O를 대폭 줄여줍니다.
Adaptive Hash Index (AHI)
InnoDB는 자주 접근되는 인덱스 페이지에 대해 해시 인덱스를 자동 생성합니다. B-Tree 탐색은 O(log n)이지만, 해시 인덱스는 O(1)이므로 특정 패턴의 쿼리 성능이 크게 향상됩니다. 단, 모든 경우에 유리한 것은 아니며, 경합이 심한 환경에서는 비활성화하는 것이 나을 수 있습니다.
Flush 메커니즘
Dirty Page는 다음 상황에서 디스크로 기록됩니다:
MySQL 8.0의 변화
MySQL 8.0에서는 Query Cache가 완전히 제거되었습니다. Query Cache는 동일한 쿼리의 결과를 캐싱했지만, 테이블이 변경되면 관련 캐시를 모두 무효화해야 해서 오히려 성능 저하를 일으키는 경우가 많았습니다. 대신 Buffer Pool과 애플리케이션 레벨 캐싱(Redis 등)을 권장합니다.
다이어그램 설명:
| 구성요소 | 저장 데이터 | 목적 | 특징 |
|---|---|---|---|
| Buffer Pool | 데이터/인덱스 페이지 | 디스크 I/O 최소화 | LRU + Midpoint 전략, 가장 중요한 캐시 |
| Change Buffer | 세컨더리 인덱스 변경사항 | 랜덤 I/O 감소 | 나중에 페이지 로드 시 병합 (Merge) |
| Adaptive Hash Index | 자주 접근하는 인덱스의 해시 | 검색 속도 향상 | 자동 생성/제거, O(1) 검색 |
| Log Buffer | Redo Log 엔트리 | 트랜잭션 내구성 | 주기적으로 디스크 Redo Log로 플러시 |
| Query Cache | 쿼리 결과 (제거됨) | 동일 쿼리 재사용 | MySQL 8.0에서 완전 제거 |