Adaptive Hash Index — InnoDB가 자동 생성하는 해시 인덱스
B+Tree 인덱스로 충분히 빠른데, InnoDB는 왜 내부적으로 해시 인덱스를 추가로 만드는 걸까요?
InnoDB는 기본적으로 B+Tree 인덱스를 사용하지만, 자주 접근되는 인덱스 페이지에 대해 자동으로 해시 인덱스를 생성합니다. 이것이 Adaptive Hash Index(AHI)입니다. DBA가 직접 제어할 수 없는 독특한 인덱스인 만큼, 동작 원리와 모니터링 방법을 알아두는 것이 중요합니다.
개념 정의
Adaptive Hash Index(AHI) 는 InnoDB가 Buffer Pool의 페이지 접근 패턴을 분석하여, 자주 접근되는 인덱스 페이지에 대해 메모리 내 해시 인덱스를 자동으로 생성하는 기능입니다.
B+Tree 검색: 루트 → 내부 노드 → 리프 노드 → O(log n), 3~4회 페이지 접근
AHI 검색: 해시 함수 → 바로 리프 노드 → O(1), 1회 접근
핵심 포인트:
- DBA가 생성/삭제할 수 없습니다 (InnoDB 자체 판단)
- B+Tree를 대체하는 것이 아니라 보조합니다
- Buffer Pool의 메모리를 사용합니다
- 항상 유리한 것은 아닙니다
왜 필요한가
B+Tree 인덱스에서 키 하나를 찾으려면 루트에서 리프까지 여러 노드를 거쳐야 합니다.
테이블 행 수: 1,000,000
B+Tree 높이: 3 (루트 → 내부 → 리프)
단일 조회당 페이지 접근: 3회
초당 10,000 조회 × 3회 = 초당 30,000 페이지 접근
AHI가 활성화되면:
초당 10,000 조회 × 1회 = 초당 10,000 페이지 접근
→ 페이지 접근 횟수 3분의 1로 감소
특히 동일한 키로 반복 조회하는 OLTP 워크로드에서 효과가 큽니다.
내부 동작
AHI 생성 조건
InnoDB는 다음 조건을 감지하면 AHI를 생성합니다.
- 특정 인덱스 페이지가 동일한 접근 패턴으로 반복 조회됨
- 해당 페이지가 충분히 자주 접근됨 (내부 카운터 기준)
- 해시 인덱스를 만드는 것이 유리하다고 판단됨
접근 패턴 감지:
같은 WHERE 조건으로 같은 인덱스 페이지에 반복 접근
→ InnoDB가 해당 검색 패턴의 해시 인덱스 자동 생성
AHI 해시 키 구성
AHI의 해시 키는 인덱스 접두사(prefix) 로 구성됩니다.
인덱스: (department, age, salary)
접근 패턴 1: WHERE department = 'Engineering'
→ 해시 키: department 값 기반
접근 패턴 2: WHERE department = 'Engineering' AND age = 28
→ 해시 키: (department, age) 값 기반
접근 패턴에 따라 해시 키의 접두사 길이가 달라집니다.
AHI의 생명 주기
1. 관찰: InnoDB가 페이지 접근 패턴 모니터링
2. 생성: 반복 접근 패턴 감지 시 해시 인덱스 생성
3. 사용: 동일 패턴 쿼리에서 B+Tree 대신 해시로 검색
4. 폐기: 접근 패턴 변경 또는 페이지가 Buffer Pool에서 제거 시 삭제
모니터링
SHOW ENGINE INNODB STATUS
SHOW ENGINE INNODB STATUS\G
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2,
0 merges
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
...
0.00 hash searches/s, 0.00 non-hash searches/s
핵심 지표:
- hash searches/s: AHI를 통한 검색 횟수
- non-hash searches/s: B+Tree를 통한 검색 횟수
- AHI 적중률:
hash searches / (hash searches + non-hash searches)
AHI 적중률 계산:
적중률 = hash_searches / (hash_searches + non_hash_searches) × 100
예: 10,000 / (10,000 + 5,000) × 100 = 66.7%
information_schema에서 확인
-- AHI 메모리 사용량 확인
SELECT
EVENT_NAME,
CURRENT_NUMBER_OF_BYTES_USED / 1024 / 1024 AS mb_used
FROM performance_schema.memory_summary_global_by_event_name
WHERE EVENT_NAME LIKE '%adaptive_hash%';
Semaphore(세마포어) 경합 확인
SHOW ENGINE INNODB STATUS\G
----------
SEMAPHORES
----------
--Thread X has waited at btr0sea.cc line 123 for 0.0001 seconds the semaphore:
btr0sea.cc에서의 대기가 빈번하면 AHI 관련 rw-lock 경합이 발생하고 있는 것입니다.
AHI의 문제점
1. rw-lock 경합
AHI 해시 테이블에 접근할 때 읽기-쓰기 잠금(rw-lock) 이 필요합니다.
동시 접근이 많은 경우:
스레드 A: AHI 읽기 (rw-lock 획득)
스레드 B: AHI 읽기 (대기...)
스레드 C: AHI 수정 (대기...)
→ 경합이 심하면 오히려 B+Tree보다 느려질 수 있음
MySQL 5.7부터 AHI 파티셔닝을 지원하여 경합을 줄입니다.
-- AHI 파티션 수 확인 (기본 8)
SHOW VARIABLES LIKE 'innodb_adaptive_hash_index_parts';
-- 경합이 심하면 파티션 수를 늘릴 수 있음 (서버 재시작 필요)
-- my.cnf: innodb_adaptive_hash_index_parts = 16
2. 메모리 오버헤드
AHI는 Buffer Pool의 메모리를 사용합니다. AHI가 지나치게 크면 Buffer Pool에서 데이터 페이지를 캐시할 수 있는 공간이 줄어듭니다.
3. 효과 없는 워크로드
다음 워크로드에서는 AHI가 도움이 되지 않습니다.
- 풀 테이블 스캔: 해시 조회가 아닌 순차 스캔
- 범위 검색: AHI는 등가 검색(=)에만 효과적
- LIKE 검색: 패턴 매칭에는 해시 적용 불가
- JOIN 결과가 큰 경우: 매칭 횟수 자체가 많음
4. 해시 충돌
해시 함수의 특성상 서로 다른 키가 같은 해시 값을 가질 수 있습니다. 충돌이 많으면 해시 체인이 길어져 성능이 저하됩니다.
비활성화 판단 기준
AHI를 비활성화해야 하는 경우
- AHI 적중률이 낮을 때 (50% 미만)
- btr0sea.cc 관련 세마포어 대기가 빈번할 때
- 대량 쓰기 워크로드 (해시 테이블 갱신 비용이 큼)
- 풀 스캔/범위 검색 위주 워크로드
비활성화 방법
-- 동적으로 비활성화 가능 (서버 재시작 불필요)
SET GLOBAL innodb_adaptive_hash_index = OFF;
-- 다시 활성화
SET GLOBAL innodb_adaptive_hash_index = ON;
-- 영구 설정 (my.cnf)
-- innodb_adaptive_hash_index = OFF
비활성화 전후 성능 비교
-- 1. 현재 상태 기록
SHOW ENGINE INNODB STATUS\G
-- hash searches/s, non-hash searches/s 기록
-- 2. AHI 비활성화
SET GLOBAL innodb_adaptive_hash_index = OFF;
-- 3. 동일 워크로드 실행 후 성능 비교
-- QPS(Queries Per Second), 응답 시간, CPU 사용률 비교
-- 4. 판단
-- 성능이 개선되면 비활성화 유지
-- 성능이 저하되면 다시 활성화
실전 시나리오
시나리오 1: OLTP 단건 조회 서버
특징: 동일한 PK로 반복 조회
AHI 효과: 높음 (동일 패턴 반복)
권장: AHI 활성화 (기본값)
시나리오 2: 배치 분석 서버
특징: 풀 스캔, 범위 검색 위주
AHI 효과: 거의 없음
권장: AHI 비활성화 (메모리 절약)
시나리오 3: 높은 동시성 웹 서버
특징: 수백 스레드 동시 접근
AHI 효과: 경합이 문제될 수 있음
권장: 모니터링 후 판단 (btr0sea.cc 대기 확인)
AHI 관련 설정 정리
| 설정 | 기본값 | 설명 |
|---|---|---|
innodb_adaptive_hash_index | ON | AHI 활성화/비활성화 |
innodb_adaptive_hash_index_parts | 8 | AHI 파티션 수 (경합 분산) |
정리
- AHI는 InnoDB가 자주 접근되는 인덱스 페이지에 대해 자동으로 생성하는 메모리 내 해시 인덱스입니다
- B+Tree의 O(log n)을 O(1)로 줄여, 반복적인 등가 조회에서 큰 효과가 있습니다
- DBA가 직접 생성/삭제할 수 없으며, InnoDB가 접근 패턴을 분석하여 자동 관리합니다
- 동시 접근이 많거나 범위 검색 위주 워크로드에서는 rw-lock 경합으로 오히려 성능이 저하될 수 있습니다
SHOW ENGINE INNODB STATUS로 hash/non-hash 비율과 세마포어 대기를 모니터링하고, 필요 시 비활성화합니다