Theme:

B+Tree 인덱스로 충분히 빠른데, InnoDB는 왜 내부적으로 해시 인덱스를 추가로 만드는 걸까요?

InnoDB는 기본적으로 B+Tree 인덱스를 사용하지만, 자주 접근되는 인덱스 페이지에 대해 자동으로 해시 인덱스를 생성합니다. 이것이 Adaptive Hash Index(AHI)입니다. DBA가 직접 제어할 수 없는 독특한 인덱스인 만큼, 동작 원리와 모니터링 방법을 알아두는 것이 중요합니다.

개념 정의

Adaptive Hash Index(AHI) 는 InnoDB가 Buffer Pool의 페이지 접근 패턴을 분석하여, 자주 접근되는 인덱스 페이지에 대해 메모리 내 해시 인덱스를 자동으로 생성하는 기능입니다.

PLAINTEXT
B+Tree 검색:  루트 → 내부 노드 → 리프 노드  →  O(log n), 3~4회 페이지 접근
AHI 검색:     해시 함수 → 바로 리프 노드      →  O(1), 1회 접근

핵심 포인트:

  • DBA가 생성/삭제할 수 없습니다 (InnoDB 자체 판단)
  • B+Tree를 대체하는 것이 아니라 보조합니다
  • Buffer Pool의 메모리를 사용합니다
  • 항상 유리한 것은 아닙니다

왜 필요한가

B+Tree 인덱스에서 키 하나를 찾으려면 루트에서 리프까지 여러 노드를 거쳐야 합니다.

PLAINTEXT
테이블 행 수: 1,000,000
B+Tree 높이: 3 (루트 → 내부 → 리프)
단일 조회당 페이지 접근: 3회

초당 10,000 조회 × 3회 = 초당 30,000 페이지 접근

AHI가 활성화되면:

PLAINTEXT
초당 10,000 조회 × 1회 = 초당 10,000 페이지 접근
→ 페이지 접근 횟수 3분의 1로 감소

특히 동일한 키로 반복 조회하는 OLTP 워크로드에서 효과가 큽니다.

내부 동작

AHI 생성 조건

InnoDB는 다음 조건을 감지하면 AHI를 생성합니다.

  1. 특정 인덱스 페이지가 동일한 접근 패턴으로 반복 조회됨
  2. 해당 페이지가 충분히 자주 접근됨 (내부 카운터 기준)
  3. 해시 인덱스를 만드는 것이 유리하다고 판단
PLAINTEXT
접근 패턴 감지:
  같은 WHERE 조건으로 같은 인덱스 페이지에 반복 접근
  → InnoDB가 해당 검색 패턴의 해시 인덱스 자동 생성

AHI 해시 키 구성

AHI의 해시 키는 인덱스 접두사(prefix) 로 구성됩니다.

PLAINTEXT
인덱스: (department, age, salary)

접근 패턴 1: WHERE department = 'Engineering'
→ 해시 키: department 값 기반

접근 패턴 2: WHERE department = 'Engineering' AND age = 28
→ 해시 키: (department, age) 값 기반

접근 패턴에 따라 해시 키의 접두사 길이가 달라집니다.

AHI의 생명 주기

PLAINTEXT
1. 관찰: InnoDB가 페이지 접근 패턴 모니터링
2. 생성: 반복 접근 패턴 감지 시 해시 인덱스 생성
3. 사용: 동일 패턴 쿼리에서 B+Tree 대신 해시로 검색
4. 폐기: 접근 패턴 변경 또는 페이지가 Buffer Pool에서 제거 시 삭제

모니터링

SHOW ENGINE INNODB STATUS

SQL
SHOW ENGINE INNODB STATUS\G
PLAINTEXT
-------------------------------------
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)
PLAINTEXT
AHI 적중률 계산:
적중률 = hash_searches / (hash_searches + non_hash_searches) × 100

예: 10,000 / (10,000 + 5,000) × 100 = 66.7%

information_schema에서 확인

SQL
-- 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(세마포어) 경합 확인

SQL
SHOW ENGINE INNODB STATUS\G
PLAINTEXT
----------
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) 이 필요합니다.

PLAINTEXT
동시 접근이 많은 경우:
스레드 A: AHI 읽기 (rw-lock 획득)
스레드 B: AHI 읽기 (대기...)
스레드 C: AHI 수정 (대기...)
→ 경합이 심하면 오히려 B+Tree보다 느려질 수 있음

MySQL 5.7부터 AHI 파티셔닝을 지원하여 경합을 줄입니다.

SQL
-- 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를 비활성화해야 하는 경우

  1. AHI 적중률이 낮을 때 (50% 미만)
  2. btr0sea.cc 관련 세마포어 대기가 빈번할 때
  3. 대량 쓰기 워크로드 (해시 테이블 갱신 비용이 큼)
  4. 풀 스캔/범위 검색 위주 워크로드

비활성화 방법

SQL
-- 동적으로 비활성화 가능 (서버 재시작 불필요)
SET GLOBAL innodb_adaptive_hash_index = OFF;

-- 다시 활성화
SET GLOBAL innodb_adaptive_hash_index = ON;

-- 영구 설정 (my.cnf)
-- innodb_adaptive_hash_index = OFF

비활성화 전후 성능 비교

SQL
-- 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 단건 조회 서버

PLAINTEXT
특징: 동일한 PK로 반복 조회
AHI 효과: 높음 (동일 패턴 반복)
권장: AHI 활성화 (기본값)

시나리오 2: 배치 분석 서버

PLAINTEXT
특징: 풀 스캔, 범위 검색 위주
AHI 효과: 거의 없음
권장: AHI 비활성화 (메모리 절약)

시나리오 3: 높은 동시성 웹 서버

PLAINTEXT
특징: 수백 스레드 동시 접근
AHI 효과: 경합이 문제될 수 있음
권장: 모니터링 후 판단 (btr0sea.cc 대기 확인)

AHI 관련 설정 정리

설정기본값설명
innodb_adaptive_hash_indexONAHI 활성화/비활성화
innodb_adaptive_hash_index_parts8AHI 파티션 수 (경합 분산)

정리

  • AHI는 InnoDB가 자주 접근되는 인덱스 페이지에 대해 자동으로 생성하는 메모리 내 해시 인덱스입니다
  • B+Tree의 O(log n)을 O(1)로 줄여, 반복적인 등가 조회에서 큰 효과가 있습니다
  • DBA가 직접 생성/삭제할 수 없으며, InnoDB가 접근 패턴을 분석하여 자동 관리합니다
  • 동시 접근이 많거나 범위 검색 위주 워크로드에서는 rw-lock 경합으로 오히려 성능이 저하될 수 있습니다
  • SHOW ENGINE INNODB STATUS로 hash/non-hash 비율과 세마포어 대기를 모니터링하고, 필요 시 비활성화합니다
댓글 로딩 중...