skip to content
Q

[DB] 비트맵 인덱스 스캔 vs 인덱스 스캔 vs 테이블 스캔

/ 8 min read

Table of Contents

비트맵 인덱스 스캔 vs 인덱스 스캔 vs 테이블 스캔 🔍

Postgres에서 쿼리를 실행할 때 데이터 검색 방법으로 테이블 스캔(Table Scan), 인덱스 스캔(Index Scan), **비트맵 인덱스 스캔(Bitmap Index Scan)**의 세 가지 주요 기법이 있다. 각 방법은 상황에 따라 성능 차이가 크며, 올바른 쿼리 최적화를 위해 이를 이해하는 것이 매우 중요하다.


1. 테이블 스캔 (Sequential Scan) 🚦

정의

**테이블 스캔(Sequential Scan)**은 Postgres에서 전체 테이블을 순차적으로 탐색하여 데이터를 검색하는 방법이다.
모든 행을 확인해야 하므로 대용량 데이터셋에서는 성능 저하가 발생할 수 있다.

사용 사례

  • WHERE 절이 없는 경우: 모든 데이터를 가져와야 하는 상황.
  • 대부분의 데이터가 필요한 경우: 특정 조건이 매우 포괄적이어서 거의 모든 데이터를 반환해야 하는 경우.
  • 인덱스 사용이 비효율적인 경우: 예를 들어, WHERE id > 100과 같이 예상되는 행이 매우 많을 때.

예시

EXPLAIN ANALYZE SELECT name FROM grades WHERE id > 100;

결과:

Seq Scan on grades (cost=0.00..1000.00 rows=5000000 width=64)
Filter: (id > 100)
  • Seq Scan: 전체 테이블을 스캔함.
  • 비용(cost): 테이블을 모두 읽기 때문에 상대적으로 높다.

2. 인덱스 스캔 (Index Scan) 🔍

정의

**인덱스 스캔(Index Scan)**은 인덱스에 저장된 값을 이용하여 특정 조건을 만족하는 데이터를 빠르게 검색하는 방법이다.
그러나 인덱스를 통해 특정 행의 위치를 찾은 후 다시 힙(Heap)으로 돌아가 데이터를 가져오는 추가 작업이 필요하다.

사용 사례

  • 정확한 단일 값 조회: WHERE id = 1000처럼 하나의 값만 필요한 경우.
  • 데이터가 적을 때: WHERE id < 100처럼 특정 범위 내 데이터가 적을 때.

예시

EXPLAIN ANALYZE SELECT name FROM grades WHERE id = 1000;

결과:

Index Scan using grades_pkey on grades (cost=0.42..4.44 rows=1 width=64)
Index Cond: (id = 1000)
  • Index Scan: 인덱스를 사용하여 데이터 위치를 찾음.
  • Heap Fetches: 인덱스에서 데이터를 찾은 후, 힙에서 실제 데이터를 가져옴.
  • 랜덤 액세스 비용: 힙 접근 시 페이지당 1회 이상의 디스크 I/O가 필요하여 데이터 양이 많아지면 비효율적이다.

3. 비트맵 인덱스 스캔 (Bitmap Index Scan) 🧮

정의

**비트맵 인덱스 스캔(Bitmap Index Scan)**은 다수의 데이터를 조회할 때 사용되며, 인덱스와 힙 간의 랜덤 액세스를 줄여주는 방식이다.
인덱스에서 데이터 페이지 위치를 비트맵(BitMap)으로 저장하고, 필요한 페이지를 한 번에 가져오는 방법으로 성능을 크게 향상시킨다.

사용 사례

  • 중간 정도의 데이터 양을 조회할 때: WHERE grade > 95처럼 결과가 많지만 전체 데이터는 아닌 경우.
  • 복합 조건 처리 시: 여러 인덱스의 비트맵을 결합하여 최적화된 데이터를 가져올 때.

비트맵 인덱스 스캔의 작동 원리

  1. 비트맵 생성: 인덱스를 스캔하여 조건에 맞는 페이지 번호를 비트맵에 기록.
  2. 비트맵 결합: 여러 인덱스의 비트맵을 논리 연산(AND, OR)으로 결합.
  3. 비트맵 힙 스캔(Bitmap Heap Scan): 최종 비트맵을 이용해 필요한 페이지를 한 번에 힙에서 가져옴.
  4. 데이터 필터링: 메모리에서 데이터를 필터링하여 최종 결과 반환.

예시

EXPLAIN ANALYZE SELECT id FROM grades WHERE grade > 95;

결과:

Bitmap Heap Scan on grades (cost=4.47..27.93 rows=1000 width=4)
Recheck Cond: (grade > 95)
Heap Blocks: exact=26
-> Bitmap Index Scan on grades_index (cost=0.00..4.47 rows=1000 width=0)
Index Cond: (grade > 95)
  • Bitmap Index Scan: 인덱스 스캔을 통해 비트맵을 생성.
  • Bitmap Heap Scan: 생성된 비트맵을 사용해 필요한 페이지를 한 번에 가져옴.
  • 효율적 메모리 사용: 메모리 내에서 데이터 필터링이 가능하여 불필요한 I/O를 줄인다.

4. 성능 비교 및 사용 사례

스캔 방법사용 사례장점단점
테이블 스캔대부분의 데이터가 필요한 경우인덱스가 필요 없으며, 순차적 I/O가 빠름불필요한 데이터도 모두 읽음
인덱스 스캔소수의 데이터만 필요할 때빠른 조회, 정확한 값 찾기에 유리많은 데이터 시 힙 접근으로 성능 저하
비트맵 인덱스 스캔중간 정도 데이터, 복합 조건 조회 시인덱스와 힙 간 랜덤 액세스 감소, 메모리 효율적 사용복잡한 논리 연산 시 성능 저하 가능

5. 결론 🎯

Postgres에서는 쿼리의 조건과 데이터 양에 따라 테이블 스캔, 인덱스 스캔, 비트맵 인덱스 스캔을 적절히 선택해야 한다.

  • 데이터가 적을 때: 인덱스 스캔을 통해 효율적으로 데이터를 조회.
  • 데이터가 많을 때: 테이블 스캔이 오히려 비용 효율적일 수 있다.
  • 중간 정도 데이터 또는 복합 조건: 비트맵 인덱스 스캔을 통해 랜덤 액세스를 줄여 성능을 높일 수 있다.

Postgres 옵티마이저는 이러한 다양한 스캔 방법을 활용하여 최적의 쿼리 실행 계획을 선택한다. 하지만 데이터 분포와 통계에 따라 잘못된 스캔 방식을 선택할 수도 있으므로, EXPLAIN ANALYZE를 활용하여 쿼리 성능을 주기적으로 모니터링하고 최적화하는 것이 필요하다.