426. 비트맵 인덱스 (Bitmap Index)
⚠️ 이 문서는 "남자이면서, 20대이면서, 서울에 사는 사람"처럼 조건이 많고 데이터 종류가 몇 개 없는(남/여) 컬럼들을 검색할 때, **B-Tree 인덱스를 쓰면 오히려 느려지는 한계를 극복하기 위해 데이터를 0과 1의 조합으로 압축하여 빛의 속도로 연산하는 '비트맵 인덱스'**를 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: 데이터의 상태를 **0(아님)과 1(맞음)**이라는 비트(Bit)의 배열로 쫙 펼쳐서 저장하는 특수한 인덱스다.
- 사용 조건 (분포도 낮음): 성별(남/여), 혈액형(A/B/O/AB), 부서명처럼 나올 수 있는 값의 종류(Cardinality)가 아주 적을 때만 쓸 수 있다.
- 가치:
AND,OR같은 다중 조건 검색을 할 때 컴퓨터가 가장 잘하는 '비트 논리 연산'을 써서 결과를 순식간에 뽑아낸다. 주로 데이터 웨어하우스(DW) 환경에서 쓰인다.
Ⅰ. 개요: B-Tree가 바보가 되는 순간 (Context & Necessity)
1,000만 명의 회원 테이블에서 성별 컬럼에 B-Tree 인덱스를 걸었다고 치자.
"성별이 남자인 사람 다 찾아줘!"
- B-Tree 인덱스: "네! 찾아보니... 어... 500만 명이나 있네요?"
- 이 500만 명의 주소를 가지고 디스크로 점프(Key Lookup, 423번 문서)를 500만 번 뛰어야 한다. (서버 터짐)
이렇게 **'값의 종류(Cardinality)가 적어서, 한 번 찾으면 너무 많은 데이터가 쏟아져 나오는 컬럼'**에는 B-Tree 인덱스를 걸면 오히려 풀 스캔보다 더 느려진다. (분포도가 나쁘다, 즉 10~15% 이상을 차지한다) 이 딜레마를 수학적으로 해결한 것이 비트맵 인덱스다.
📢 섹션 요약 비유: 비트맵 인덱스는 학교에서 **'체육대회 청기백기 들기'**와 같습니다. 반장(B-Tree)이 "남자애들 일어서!"라고 이름 부르는 대신, "남자애들 청기 들어! 20대 백기 들어!"라고 하면 운동장에 앉아있는 100만 명 중 청기와 백기를 동시에 든 사람만 0.1초 만에 눈으로 싹 골라낼 수 있습니다.
Ⅱ. 비트맵 인덱스의 작동 원리 ★
비트맵 인덱스는 내부적으로 0과 1로 된 거대한 지도를 만든다.
| ID | 이름 | 성별 | 지역 |
|---|---|---|---|
| 1 | 철수 | 남 | 서울 |
| 2 | 영희 | 여 | 부산 |
| 3 | 민수 | 남 | 서울 |
1. 인덱스 생성 (0과 1의 지도)
- 성별 인덱스:
- 남:
[1, 0, 1](1, 3번이 남자) - 여:
[0, 1, 0](2번이 여자)
- 남:
- 지역 인덱스:
- 서울:
[1, 0, 1] - 부산:
[0, 1, 0]
- 서울:
2. 다중 조건 검색 (Bitwise AND 연산)
- 질문: "남자(
AND) 서울 사람 찾아줘!" - 연산: 컴퓨터는 하드디스크를 안 뒤지고, 아까 만든 0과 1의 지도 두 장만 꺼내서 겹쳐본다.
- 남자 지도:
[1, 0, 1] - 서울 지도:
[1, 0, 1] - AND 결과:
[1, 0, 1]
- 남자 지도:
- 0.0001초 만에 "1번과 3번 데이터다!"라는 결론을 내고, 딱 두 번만 디스크로 점프해서 가져온다. 속도가 사기적이다.
Ⅲ. 치명적 단점: 쓰기(Write) 락(Lock)의 지옥
비트맵 인덱스는 조회(SELECT)에는 신이지만, 삽입/수정(INSERT/UPDATE)에는 최악의 쥐약이다.
- 만약 4번 회원이 새로 가입했다.
- 성별 인덱스:
[1, 0, 1, 0]으로 배열을 고쳐야 한다. - 문제는 배열을 고치는 아주 짧은 찰나에, **저 지도 전체에 엄청나게 넓은 락(Table-level Lock)**이 걸려버린다는 것이다.
- 즉, 쇼핑몰에 손님이 한 명 가입할 때마다 다른 사람들은 조회조차 멈추게 된다.
그래서 비트맵 인덱스는 실시간으로 주문이 쏟아지는 OLTP(운영 DB) 환경에서는 절대 쓸 수 없다. 대신, 매일 밤 12시에 데이터를 쏟아붓고 낮에는 조회만 100만 번 일어나는 데이터 웨어하우스(OLAP - 321번 문서) 환경에서만 쓰이는 귀족 인덱스다.
┌──────────────────────────────────────────────────────────────┐
│ 비트맵 인덱스의 비트 논리 연산(Bitwise AND) 시각화 │
├──────────────────────────────────────────────────────────────┤
│ │
│ Q. "직급이 [대리]이면서, [개발팀]인 사람을 찾아라!" │
│ │
│ [ 🗺️ 비트맵 인덱스 지도 ] │
│ 직급(대리) 지도: 1 0 1 0 0 1 0 (1, 3, 6번이 대리) │
│ 부서(개발팀)지도: 0 0 1 1 0 1 0 (3, 4, 6번이 개발팀) │
│ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │
│ [ ⚡ AND 연산 ] : 0 0 1 0 0 1 0 ◀── 컴퓨터가 젤 잘하는 계산! │
│ │
│ ★ 결론: 3번, 6번 사원을 가져오면 끝. (디스크 뒤질 필요도 없음) │
└──────────────────────────────────────────────────────────────┘
Ⅳ. 결론
"인덱스의 선택은 데이터의 카디널리티(분포도)가 결정한다." 개발자가 "이 컬럼은 나이, 성별, 부서처럼 뻔한 값만 들어가니까 인덱스 걸면 빠르겠지?"라고 B-Tree 인덱스를 거는 순간, 그 DB는 풀 스캔보다 못한 최악의 성능을 보여주게 된다. 분포도(카디널리티)가 나쁜 컬럼들의 다중 조건 검색을 처리할 수 있는 유일한 무기는 비트맵 인덱스뿐이다. 데이터의 생김새(다양성)를 분석하지 않고 무지성으로 걸어대는 인덱스만큼 시스템을 망치는 독약은 없다.
📌 관련 개념 맵
- 대척점 자료구조: B-Tree 인덱스 (422번 문서 - 고유한 값이 많은 PK 검색에 특화)
- 사용 환경: OLAP, 데이터 웨어하우스 (DW - 321번 문서)
- 제한 사항: OLTP (온라인 트랜잭션 처리) 환경에서는 성능 폭락
- 핵심 조건 키워드: Low Cardinality (카디널리티 낮음), 분포도 낮음
👶 어린이를 위한 3줄 비유 설명
- B-Tree 인덱스는 1만 명의 얼굴을 일일이 기억하고 찾는 거라면, 비트맵 인덱스는 친구들에게 '안경 썼음=O, 안 썼음=X'라고 크게 팻말을 들게 하는 거예요.
- "안경 쓰고 모자 쓴 친구 나와!"라고 하면, 선생님은 팻말 두 개가 다 'O'인 친구만 쓱 골라내면 되니까 1초 만에 찾을 수 있죠.
- 하지만 누가 안경을 벗었다 썼다 할 때마다(데이터 수정) 반 전체가 팻말을 고쳐 쓰는라 시간이 오래 걸려서 멈춰 있어야 한다는 단점이 있답니다!