PostgreSQL의 9가지 인덱스 유형에 대한 완벽한 가이드
Lukas Schneider
DevOps Engineer · Leapcell

PostgreSQL의 9가지 인덱스 유형에 대한 완벽한 가이드
PostgreSQL은 다양한 인덱스 유형을 제공합니다. 각 인덱스 유형은 특정 데이터 구조와 원칙을 기반으로 하며, 다양한 응용 시나리오에 적합합니다. 다음은 이러한 9가지 주요 인덱스 유형에 대한 자세한 소개입니다.
PostgreSQL의 9가지 주요 인덱스 유형에 대한 자세한 설명
PostgreSQL은 다양한 인덱스 유형을 제공합니다. 각 인덱스 유형은 특정 데이터 구조와 원칙을 기반으로 하며, 다양한 응용 시나리오에 적합합니다. 다음은 이러한 9가지 주요 인덱스 유형에 대한 자세한 소개입니다.
1. B - 트리 인덱스
데이터 구조
B - 트리(균형 다방향 검색 트리)는 자체 균형 트리 구조입니다. 그 안의 각 노드는 여러 자식 노드(다방향)를 가질 수 있습니다. 일반적으로 B - 트리 노드는 여러 키-값 쌍과 자식 노드에 대한 포인터를 포함합니다. 예를 들어, m차 B - 트리 노드는 최대 m개의 자식 노드를 가질 수 있으며, 최소 ⌈m/2⌉개의 자식 노드를 가질 수 있습니다(루트 노드 제외).
개략도
+--------------------+ | 10 | 20 | 30 | +--------------------+ / | \ +---------+ +---------+ +---------+ | 1 | 5 | | 11 | 15 | | 21 | 25 | +---------+ +---------+ +---------+
원리
B - 트리 인덱스는 가장 일반적으로 사용되는 인덱스 유형이며 대부분의 데이터 유형에 적합합니다. 균형 잡힌 트리 구조를 통해 범위 쿼리, 동등성 쿼리 및 정렬 작업을 효율적으로 수행할 수 있습니다. 쿼리를 수행할 때 루트 노드에서 시작하여 대상 노드를 찾거나 대상이 존재하지 않는다고 판단될 때까지 키 값의 크기 관계에 따라 아래로 재귀적으로 검색합니다.
응용 시나리오
- 동등성 쿼리 (=): 특정 값을 찾아야 할 때 B - 트리는 해당 값을 포함하는 노드를 빠르게 찾을 수 있습니다. 예를 들어, 사용자 테이블에서 사용자 ID가 100인 사용자를 찾습니다.
- 범위 쿼리 (>, <, >=, <=): 특정 범위 내의 값을 찾아야 하는 쿼리의 경우 B - 트리는 정렬성을 사용하여 범위의 시작 및 종료 노드를 효율적으로 찾은 다음 이러한 노드를 순회하여 결과를 얻을 수 있습니다. 예를 들어, 나이가 20세에서 30세 사이인 사용자를 찾습니다.
- 정렬 작업 (ORDER BY): B - 트리의 키 값은 정렬된 방식으로 저장되므로 인덱스를 정렬에 직접 사용할 수 있어 데이터에 대한 추가 정렬 작업을 피하고 정렬 효율성을 높일 수 있습니다.
생성 구문
CREATE INDEX idx_btree ON table_name (column_name);
2. 해시 인덱스
데이터 구조
해시 인덱스는 해시 테이블 구조를 사용합니다. 해시 함수를 통해 키 값을 해시 테이블의 슬롯에 매핑합니다. 해시 테이블은 일반적으로 배열이며 각 슬롯은 하나 이상의 키-값 쌍을 저장할 수 있습니다. 해시 충돌이 발생하면 일반적으로 연결 목록 방법 또는 개방 주소 지정 방법을 사용하여 처리합니다.
개략도
+---+---+---+---+ | 0 | 1 | 2 | 3 | +---+---+---+---+ | | | 10->20| | | | | +---+---+---+---+
원리
해시 인덱스는 해시 함수를 통해 키 값을 고정 길이 해시 코드로 변환한 다음 해시 코드에 따라 해당 슬롯을 찾습니다. 해시 함수는 키 값의 순서를 보장할 수 없으므로 동등성 쿼리에만 적합하며 범위 쿼리 및 정렬 작업은 지원하지 않습니다.
응용 시나리오
- 동등성 쿼리 (=): 특정 값을 정확하게 일치시켜야 할 때 해시 인덱스는 해시 함수를 통해 슬롯을 빠르게 계산하여 대상 데이터를 찾을 수 있습니다. 예를 들어, 캐시 테이블에서 특정 캐시 키에 해당하는 값을 찾습니다.
생성 구문
CREATE INDEX idx_hash ON table_name USING hash (column_name);
3. GiST 인덱스
데이터 구조
GiST(Generalized Search Tree)는 일반 검색 트리 구조입니다. 해당 노드는 다양한 유형의 데이터와 연산자 클래스를 저장할 수 있습니다. 각 노드는 일반적으로 여러 키-값 쌍과 자식 노드에 대한 포인터를 포함하며, 다양한 데이터 유형과 연산자에 따라 사용자 정의 분할 및 병합 작업을 수행할 수 있습니다.
개략도
+--------------------+ | Rect1 | Rect2 | | +--------------------+ / | \ +---------+ +---------+ +---------+ | Point1 | | Point2 | | Point3 | +---------+ +---------+ +---------+
원리
GiST 인덱스는 여러 데이터 유형과 연산자 클래스를 지원하는 일반 인덱스 구조입니다. 데이터를 데이터 공간을 재귀적으로 분할하여 트리 구조로 구성하여 효율적인 쿼리를 달성합니다. 쿼리를 수행할 때 쿼리 조건과 연산자 클래스에 따라 루트 노드에서 시작하여 조건을 충족하는 노드를 찾을 때까지 아래로 재귀적으로 검색합니다.
응용 시나리오
- 전체 텍스트 검색: 텍스트 데이터를 토큰화한 다음 GiST 인덱스를 사용하여 이러한 토큰을 저장하고 쿼리할 수 있습니다. 예를 들어, 기사 테이블에서 키워드 검색을 수행합니다.
- 기하학적 데이터 쿼리: 점, 선 및 평면과 같은 기하학적 데이터의 경우 GiST 인덱스는 포함 및 교차와 같은 공간 쿼리를 효율적으로 처리할 수 있습니다. 예를 들어, 지도 응용 프로그램에서 특정 영역 내의 모든 관심 지점을 찾습니다.
- 다차원 데이터 쿼리: 다차원 배열 및 벡터와 같은 다차원 데이터를 처리하는 데 적합합니다. 예를 들어, 기계 학습 응용 프로그램에서 고차원 특징 벡터를 쿼리합니다.
생성 구문
CREATE INDEX idx_gist ON table_name USING gist (column_name);
4. SP - GiST 인덱스
데이터 구조
SP - GiST(Space - Partitioned GiST)는 공간 분할 GiST 인덱스입니다. 데이터 공간을 분할하여 데이터를 트리 구조로 구성합니다. 각 노드에는 여러 파티션과 자식 노드에 대한 포인터가 포함되어 있으며, 파티션은 데이터 분포에 따라 동적으로 조정할 수 있습니다.
개략도
+--------------------+ | Part1 | Part2 | | +--------------------+ / | \ +---------+ +---------+ +---------+ | SubP1 | | SubP2 | | SubP3 | +---------+ +---------+ +---------+
원리
SP - GiST 인덱스는 불균형 데이터 분포를 처리하는 데 적합합니다. 데이터 공간을 분할하고 데이터를 다른 노드에 고르게 배포하여 쿼리 효율성을 향상시킵니다. 쿼리를 수행할 때 쿼리 조건과 파티션 정보에 따라 루트 노드에서 시작하여 조건을 충족하는 노드를 찾을 때까지 아래로 재귀적으로 검색합니다.
응용 시나리오
- 다차원 데이터 쿼리: 다차원 배열 및 벡터와 같은 다차원 데이터의 경우 SP - GiST 인덱스는 데이터 분포에 따라 데이터를 분할하여 쿼리 효율성을 향상시킬 수 있습니다. 예를 들어, 지리 정보 시스템에서 다차원 지리 데이터를 쿼리합니다.
- 희소 데이터 쿼리: 데이터 집합에 많은 양의 희소 데이터가 있는 경우 SP - GiST 인덱스는 이 데이터를 효과적으로 처리하고 희소 데이터를 처리할 때 기존 인덱스의 성능 문제를 방지할 수 있습니다.
생성 구문
CREATE INDEX idx_spgist ON table_name USING spgist (column_name);
5. GIN 인덱스
데이터 구조
GIN(Generalized Inverted Index)은 역 인덱스입니다. 각 키 값의 발생 위치를 목록에 기록합니다. 특히 키 값에서 문서 ID 목록으로의 매핑을 유지 관리합니다. 여기서 문서 ID는 해당 키 값을 포함하는 레코드를 나타냅니다.
개략도
+------+-----------------+ | Key | Document IDs | +------+-----------------+ | A | 1, 3, 5 | | B | 2, 4 | +------+-----------------+
원리
GIN 인덱스는 다중 값 열과 전체 텍스트 검색에 적합합니다. 각 키 값의 발생 위치를 기록하여 효율적인 쿼리를 달성합니다. 쿼리를 수행할 때 쿼리 조건에 따라 해당 키 값을 찾은 다음 해당 키 값을 포함하는 문서 ID 목록을 가져와서 대상 데이터를 찾습니다.
응용 시나리오
- 배열 쿼리: 테이블의 특정 열이 배열 유형인 경우 GIN 인덱스는 특정 요소를 포함하는 배열을 효율적으로 쿼리할 수 있습니다. 예를 들어, 제품 테이블에서 특정 태그를 포함하는 제품을 찾습니다.
- JSON 데이터 쿼리: JSON 데이터의 경우 GIN 인덱스는 JSON의 키-값 쌍을 인덱싱하여 효율적인 JSON 데이터 쿼리를 달성할 수 있습니다. 예를 들어, 사용자 테이블에서 특정 속성을 가진 사용자를 찾습니다.
- 전체 텍스트 검색: GIN 인덱스는 텍스트 데이터를 토큰화한 다음 각 토큰의 발생 위치를 기록하여 효율적인 전체 텍스트 검색을 달성할 수 있습니다. 예를 들어, 뉴스 테이블에서 키워드 검색을 수행합니다.
생성 구문
CREATE INDEX idx_gin ON table_name USING gin (column_name);
6. BRIN 인덱스
데이터 구조
BRIN(Block Range INdex)은 블록 범위 인덱스입니다. 각 데이터 블록의 최소값과 최대값을 저장하여 인덱스 크기를 줄입니다. 인덱스 파일은 일련의 블록 범위 항목으로 구성되며 각 항목에는 데이터 블록의 시작 블록 번호, 종료 블록 번호, 최소값 및 최대값이 포함됩니다.
개략도
+---------------------+ | Block Range | Min | Max | +---------------------+ | 0 - 10 | 1 | 10 | | 11 - 20 | 11 | 20 | +---------------------+
원리
BRIN 인덱스는 매우 큰 테이블에 적합합니다. 각 블록 범위의 최소값과 최대값을 저장하여 쿼리를 수행할 때 데이터 블록이 쿼리 조건을 충족하는 데이터를 포함할 수 있는지 여부를 빠르게 판단하여 스캔해야 하는 데이터 블록 수를 줄일 수 있습니다. 그러나 블록 범위의 경계 정보만 기록하므로 쿼리 성능이 비교적 낮습니다.
응용 시나리오
- 매우 큰 테이블: 테이블에 많은 양의 데이터가 있는 경우 BRIN 인덱스를 사용하면 인덱스의 저장 공간을 크게 줄이고 인덱스 유지 관리 효율성을 높일 수 있습니다. 예를 들어, 로그 테이블에 많은 양의 로그 레코드를 저장합니다.
- 순서대로 삽입된 데이터: 데이터가 순서대로 삽입된 경우 인접한 데이터 블록의 데이터는 특정 순서를 가지며 BRIN 인덱스는 더 나은 역할을 할 수 있습니다. 예를 들어, 시계열 데이터에서 연대순으로 삽입된 데이터는 BRIN 인덱스를 사용하여 효율적으로 쿼리할 수 있습니다.
생성 구문
CREATE INDEX idx_brin ON table_name USING brin (column_name);
7. 비트맵 인덱스
데이터 구조
비트맵 인덱스는 비트맵 구조를 사용합니다. 각기 다른 키 값에 대해 비트맵을 유지 관리하고 비트맵의 각 비트는 레코드에 해당합니다. 비트가 1이면 해당 레코드가 해당 키 값을 포함한다는 의미이고, 0이면 포함하지 않는다는 의미입니다.
개략도
+------+---------------------+ | Key | Bitmap | +------+---------------------+ | A | 1 0 1 0 1 | | B | 0 1 0 1 0 | +------+---------------------+
원리
비트맵 인덱스는 카디널리티가 낮은 열(즉, 열에 서로 다른 값이 거의 없음)에 적합합니다. 비트맵의 비트 연산을 통해 여러 조건의 효율적인 결합 쿼리를 실현합니다. 쿼리를 수행할 때 쿼리 조건에 따라 해당 비트맵을 찾은 다음 비트 연산을 수행하여 조건을 충족하는 레코드의 비트맵을 가져오고 마지막으로 비트맵에 따라 대상 데이터를 찾습니다.
응용 시나리오
- 카디널리티가 낮은 열: 열에 서로 다른 값이 거의 없는 경우 비트맵 인덱스를 사용하면 인덱스의 저장 공간을 크게 줄이고 쿼리 효율성을 높일 수 있습니다. 예를 들어, 성별 열에는 "남성"과 "여성"의 두 가지 값만 있습니다.
- 여러 조건의 결합 쿼리: 비트맵 인덱스는 비트 연산을 통해 여러 조건의 비트맵을 빠르게 병합하여 최종 쿼리 결과를 얻을 수 있으므로 여러 조건의 결합 쿼리에 매우 효과적입니다. 예를 들어, 사용자 테이블에서 여성이고 나이가 20세에서 30세 사이인 사용자를 찾습니다.
생성 구문
-- PostgreSQL 자체에는 비트맵 인덱스를 생성하기 위한 직접적인 구문이 없지만 B - 트리 인덱스를 결합하여 유사한 효과를 얻을 수 있습니다. CREATE INDEX idx_bitmap ON table_name (column_name);
8. 부분 인덱스
데이터 구조
부분 인덱스의 데이터 구조는 일반 인덱스와 동일하지만 테이블의 일부 데이터에 대해서만 인덱스를 생성한다는 점이 다릅니다. 조건식을 추가하여 조건을 충족하는 데이터만 포함합니다.
개략도
원본 테이블: +----+-------+ | ID | Value | +----+-------+ | 1 | A | | 2 | B | | 3 | A | +----+-------+ 부분 인덱스(Value = 'A'): +----+-------+ | ID | Value | +----+-------+ | 1 | A | | 3 | A | +----+-------+
원리
부분 인덱스는 일부 데이터에 대해서만 인덱스를 생성하여 인덱스의 크기와 유지 관리 비용을 줄이고 인덱스 효율성을 향상시킵니다. 쿼리를 수행할 때 조건에 맞는 데이터만 인덱싱되므로 불필요한 인덱스 스캔을 줄일 수 있습니다.
응용 시나리오
- 일부 데이터만 인덱싱: 테이블의 일부 데이터만 인덱싱해야 하는 경우 부분 인덱스를 사용할 수 있습니다. 예를 들어, 사용자 테이블에서 활성 사용자만 인덱싱합니다.
- 인덱스 효율성 향상: 인덱스의 데이터 양을 줄임으로써 부분 인덱스는 인덱스의 쿼리 및 유지 관리 효율성을 향상시킬 수 있습니다. 예를 들어, 로그 테이블에서 가장 최근 달의 로그만 인덱싱합니다.
생성 구문
CREATE INDEX idx_partial ON table_name (column_name) WHERE condition;
9. 고유 인덱스
데이터 구조
고유 인덱스의 데이터 구조는 일반 인덱스와 동일하며 일반적으로 B - 트리 또는 기타 적합한 인덱스 구조를 사용합니다. 그 특징은 인덱스 열의 모든 값이 고유한지 확인하는 것입니다.
개략도
+----+-------+ | ID | Value | +----+-------+ | 1 | A | | 2 | B | | 3 | C | +----+-------+
원리
고유 인덱스는 데이터를 삽입하거나 업데이트할 때 인덱스 열의 값이 고유한지 확인하여 인덱스 열의 모든 값이 고유한지 확인합니다. 고유성 제약 조건이 위반되면 작업이 거부됩니다.
응용 시나리오
- 기본 키 제약 조건: 고유 인덱스를 사용하여 기본 키 제약 조건을 구현하여 테이블의 각 행에 고유 식별자가 있는지 확인할 수 있습니다. 예를 들어, 사용자 테이블에서 사용자 ID를 기본 키로 사용합니다.
- 고유 제약 조건: 특정 열의 값이 고유한지 확인해야 하지만 기본 키가 아닌 경우 고유 인덱스를 사용할 수 있습니다. 예를 들어, 이메일 테이블에서 이메일 주소를 고유 제약 조건으로 사용합니다.
생성 구문
CREATE UNIQUE INDEX idx_unique ON table_name (column_name);
Leapcell: 최고의 서버리스 웹 호스팅
마지막으로 웹 서비스 배포에 가장 적합한 플랫폼인 **Leapcell**을 추천합니다.
🚀 좋아하는 언어로 빌드
JavaScript, Python, Go 또는 Rust로 손쉽게 개발하세요.
🌍 무제한 프로젝트를 무료로 배포
사용한 만큼만 지불하세요. 요청도 없고, 요금도 없습니다.
⚡ 사용량에 따라 지불하고 숨겨진 비용 없음
유휴 요금 없이 원활한 확장성만 제공합니다.
🔹 Twitter에서 팔로우하세요: @LeapcellHQ