PostgreSQLの9つのインデックスタイプ完全ガイド


[![Group2233.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4075813/05d5638d-2899-48dc-8e51-ce96d3c1c0c7.png)](https://leapcell.io/)



**[Leapcell: The Best of Serverless Web Hosting](https://leapcell.io/)**

# PostgreSQLにおける9つの主要なインデックスタイプの詳細解説

PostgreSQLは、豊富な種類のインデックスタイプを提供しています。各インデックスタイプは特定のデータ構造と原理に基づいており、異なるアプリケーションシナリオに適しています。以下では、これらの9つの主要なインデックスタイプについて詳細に紹介します。

## 1. B - ツリーインデックス
### データ構造
B - ツリー（バランス付きの多方向検索木）は、自己バランス木構造です。その各ノードは複数の子ノード（多方向）を持つことができます。通常、B - ツリーノードは複数のキー値ペアと子ノードへのポインタを含みます。例えば、m次のB - ツリーノードは最大m個の子ノードを持ち、最小で⌈m/2⌉個の子ノード（ルートノードを除く）を持ちます。

### 模式図
```plaintext
           +---------------------+
           |  10  |  20  |  30   |
           +---------------------+
          /        |         \
 +---------+    +---------+    +---------+
 |  1 |  5  |    | 11 | 15  |    | 21 | 25  |
 +---------+    +---------+    +---------+
```

### 原理
B - ツリーインデックスは最も一般的に使用されるインデックスタイプであり、ほとんどのデータ型に適しています。そのバランス木構造により、効率的に範囲検索、等価検索、ソート操作を行うことができます。検索を行うときは、ルートノードから始まり、キー値のサイズ関係に従って再帰的に下方向に検索し、ターゲットノードを見つけるか、ターゲットが存在しないことを判定するまで続けます。

### アプリケーションシナリオ
- **等価検索（=）**: 特定の値を見つける必要があるとき、B - ツリーはその値を含むノードを迅速に位置付けることができます。例えば、ユーザテーブルで、ユーザIDが100のユーザを探す場合です。
- **範囲検索（>, <, >=, <=）**: ある範囲内の値を見つける必要がある検索に対して、B - ツリーはその順序性を利用して範囲の開始ノードと終了ノードを効率的に位置付け、そのノードをトラバースして結果を得ることができます。例えば、年齢が20から30のユーザを探す場合です。
- **ソート操作（ORDER BY）**: B - ツリー内のキー値は順序付けされて格納されているため、インデックスを直接ソートに使用することができ、データに追加のソート操作を行う必要がなく、ソート効率を向上させます。

### 作成文
```sql
CREATE INDEX idx_btree ON table_name (column_name);
```

## 2. ハッシュインデックス
### データ構造
ハッシュインデックスは、ハッシュテーブル構造を使用しています。キー値をハッシュ関数を通じてハッシュテーブル内のスロットにマッピングします。ハッシュテーブルは通常配列であり、各スロットは1つ以上のキー値ペアを格納することができます。ハッシュ衝突が発生した場合、通常は連結リスト方式またはオープンアドレッシング方式を使用して対処します。

### 模式図
```plaintext
+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+
|   |   | 10->20|
|   |   |       |
+---+---+---+---+
```

### 原理
ハッシュインデックスは、キー値をハッシュ関数を通じて固定長のハッシュコードに変換し、そのハッシュコードに基づいて対応するスロットを見つけます。等価検索にのみ適しています。なぜなら、ハッシュ関数はキー値の順序を保証できないため、範囲検索やソート操作をサポートしないからです。

### アプリケーションシナリオ
- **等価検索（=）**: 特定の値を正確に一致させる必要があるとき、ハッシュインデックスはハッシュ関数を通じてスロットを迅速に計算し、ターゲットデータを位置付けることができます。例えば、キャッシュテーブルで、特定のキャッシュキーに対応する値を探す場合です。

### 作成文
```sql
CREATE INDEX idx_hash ON table_name USING hash (column_name);
```

## 3. GiSTインデックス
### データ構造
GiST（Generalized Search Tree）は、一般的な検索木構造です。そのノードは異なる種類のデータと演算子クラスを格納できます。各ノードは通常複数のキー値ペアと子ノードへのポインタを含み、異なるデータ型や演算子に応じてカスタマイズされた分割とマージ操作を行うことができます。

### 模式図
```plaintext
           +---------------------+
           |  Rect1 |  Rect2  |   |
           +---------------------+
          /        |         \
 +---------+    +---------+    +---------+
 | Point1 |    | Point2  |    | Point3  |
 +---------+    +---------+    +---------+
```

### 原理
GiSTインデックスは、複数のデータ型と演算子クラスをサポートする一般的なインデックス構造です。データ空間を再帰的に分割することでデータを木構造に整理し、効率的な検索を実現します。検索を行うときは、検索条件と演算子クラスに応じて、ルートノードから再帰的に下方向に検索し、条件を満たすノードを見つけるまで続けます。

### アプリケーションシナリオ
- **全文検索**: テキストデータをトークン化し、そのトークンをGiSTインデックスを使用して格納および検索することができます。例えば、記事テーブルでキーワード検索を行う場合です。
- **幾何データ検索**: 点、線、面などの幾何データに対して、GiSTインデックスは空間検索（包含関係や交差関係など）を効率的に処理することができます。例えば、地図アプリケーションで、あるエリア内の全てのポイントを探す場合です。
- **多次元データ検索**: 多次元配列やベクトルなどの多次元データの処理に適しています。例えば、機械学習アプリケーションで高次元の特徴ベクトルを検索する場合です。

### 作成文
```sql
CREATE INDEX idx_gist ON table_name USING gist (column_name);
```

## 4. SP - GiSTインデックス
### データ構造
SP - GiST（Space - Partitioned GiST）は、空間分割型のGiSTインデックスです。データ空間を分割することでデータを木構造に整理します。各ノードは複数の分割領域と子ノードへのポインタを含み、データの分布に応じて分割領域を動的に調整することができます。

### 模式図
```plaintext
           +---------------------+
           |  Part1 |  Part2  |   |
           +---------------------+
          /        |         \
 +---------+    +---------+    +---------+
 | SubP1   |    | SubP2   |    | SubP3   |
 +---------+    +---------+    +---------+
```

### 原理
SP - GiSTインデックスは、不均衡なデータ分布を処理するのに適しています。データ空間を分割し、データを異なるノードに均等に分散させることで、検索効率を向上させます。検索を行うときは、検索条件と分割情報に応じて、ルートノードから再帰的に下方向に検索し、条件を満たすノードを見つけるまで続けます。

### アプリケーションシナリオ
- **多次元データ検索**: 多次元配列やベクトルなどの多次元データに対して、SP - GiSTインデックスはデータの分布に応じてデータを分割し、検索効率を向上させることができます。例えば、地理情報システムで多次元の地理データを検索する場合です。
- **疎データ検索**: データセットに大量の疎データが存在する場合、SP - GiSTインデックスはこのデータを効果的に処理し、伝統的なインデックスが疎データを処理する際に起こるパフォーマンス問題を回避することができます。

### 作成文
```sql
CREATE INDEX idx_spgist ON table_name USING spgist (column_name);
```

## 5. GINインデックス
### データ構造
GIN（Generalized Inverted Index）は、逆インデックスです。各キー値の出現位置をリストとして記録します。具体的には、キー値から文書IDのリストへのマッピングを維持し、文書IDはそのキー値を含むレコードを表します。

### 模式図
```plaintext
+------+-----------------+
| Key  | Document IDs    |
+------+-----------------+
|  A   |  1, 3, 5        |
|  B   |  2, 4           |
+------+-----------------+
```

### 原理
GINインデックスは、多値カラムや全文検索に適しています。各キー値の出現位置を記録することで、効率的な検索を実現します。検索を行うときは、検索条件に応じて対応するキー値を見つけ、そのキー値を含む文書IDのリストを取得し、ターゲットデータを位置付けます。

### アプリケーションシナリオ
- **配列検索**: テーブル内の特定のカラムが配列型である場合、GINインデックスは特定の要素を含む配列を効率的に検索することができます。例えば、商品テーブルで特定のタグを含む商品を探す場合です。
- **JSONデータ検索**: JSONデータに対して、GINインデックスはJSON内のキー値ペアをインデックス化し、効率的なJSONデータ検索を実現することができます。例えば、ユーザテーブルで特定の属性を持つユーザを探す場合です。
- **全文検索**: GINインデックスはテキストデータをトークン化し、各トークンの出現位置を記録することで、効率的な全文検索を実現します。例えば、ニューステーブルでキーワード検索を行う場合です。

### 作成文
```sql
CREATE INDEX idx_gin ON table_name USING gin (column_name);
```

## 6. BRINインデックス
### データ構造
BRIN（Block Range INdex）は、ブロック範囲インデックスです。各データブロックの最小値と最大値を格納することで、インデックスのサイズを削減します。インデックスファイルは一連のブロック範囲エントリから構成され、各エントリはデータブロックの開始ブロック番号、終了ブロック番号、最小値、最大値を含みます。

### 模式図
```plaintext
+---------------------+
| Block Range | Min | Max |
+---------------------+
|  0 - 10     |  1  | 10  |
| 11 - 20     | 11  | 20  |
+---------------------+
```

### 原理
BRINインデックスは、非常に大きなテーブルに適しています。各ブロック範囲の最小値と最大値を格納することで、検索を行うときに、あるデータブロックが検索条件を満たすデータを含む可能性があるかどうかを迅速に判定でき、必要なデータブロックのスキャン数を減らすことができます。ただし、ブロック範囲の境界情報のみを記録するたデータを記録するため、検索性能は比較的低いです。

### アプリケーションシナリオ
- **非常に大きなテーブル**: テーブルに大量のデータがある場合、BRINインデックスを使用すると、インデックスの格納スペースを大幅に削減でき、インデックスの保守効率を向上させることができます。例えば、ログテーブルに大量のログレコードを格納する場合です。
- **順序で挿入されるデータ**: データが順序で挿入される場合、隣接するデータブロック内のデータには一定の順序があり、BRINインデックスはより良い効果を発揮することができます。例えば、時系列データでは、日時順に挿入されるデータをBRINインデックスを使用して効率的に検索することができます。

### 作成文
```sql
CREATE INDEX idx_brin ON table_name USING brin (column_name);
```

## 7. ビットマップインデックス
### データ構造
ビットマップインデックスはビットマップ構造を使用します。各異なるキー値に対して、ビットマップを維持し、ビットマップの各ビットは1つのレコードに対応します。ビットが1の場合、対応するレコードがそのキー値を含むことを意味します。0の場合、含まないことを意味します。

### 模式図
```plaintext
+------+---------------------+
| Key  | Bitmap              |
+------+---------------------+
|  A   |  1 0 1 0 1          |
|  B   |  0 1 0 1 0          |
+------+---------------------+
```

### 原理
ビットマップインデックスは、低基数のカラム（つまり、カラム内の異なる値が少ない場合）に適しています。ビットマップのビット演算を通じて、複数条件の効率的な結合検索を実現します。検索を行うときは、検索条件に応じて対応するビットマップを見つけ、ビット演算を行って条件を満たすレコードのビットマップを取得し、最後にビットマップに基づいてターゲットデータを位置付けます。

### アプリケーションシナリオ
- **低基数のカラム**: カラム内の異なる値が少ない場合、ビットマップインデックスを使用すると、インデックスの格納スペースを大幅に削減でき、検索効率を向上させることができます。例えば、性別のカラムでは、「男性」と「女性」の2つの値しかない場合です。
- **複数条件の結合検索**: ビットマップインデックスは、複数条件の結合検索に非常に有効です。ビット演算を通じて、複数条件のビットマップを迅速にマージし、最終的な検索結果を取得することができます。例えば、ユーザテーブルで、女性で年齢が20から30のユーザを探す場合です。

### 作成文
```sql
-- PostgreSQL自体にはビットマップインデックスを作成する直接的な構文はありませんが、B - ツリーインデックスを組み合わせて同様の効果を得ることができます
CREATE INDEX idx_bitmap ON table_name (column_name);
```

## 8. 部分インデックス
### データ構造
部分インデックスのデータ構造は通常のインデックスと同じですが、テーブル内のデータの一部のみにインデックスを作成します。条件式を追加することで、条件を満たすデータのみを含みます。

### 模式図
```plaintext
元のテーブル:
+----+-------+
| ID | Value |
+----+-------+
| 1  |  A    |
| 2  |  B    |
| 3  |  A    |
+----+-------+

部分インデックス（Value = 'A'）:
+----+-------+
| ID | Value |
+----+-------+
| 1  |  A    |
| 3  |  A    |
+----+-------+
```

### 原理
部分インデックスは、データの一部のみにインデックスを作成することで、インデックスのサイズと保守コストを削減し、インデックスの効率を向上させます。検索を行うときは、条件を満たすデータのみをインデックス化し、不要なインデックススキャンを減らすことができます。

### アプリケーションシナリオ
- **データの一部のみをインデックス化**: テーブル内のデータの一部のみにインデックスを作成する必要がある場合、部分インデックスを使用することができます。例えば、ユーザテーブルで、アクティブなユーザのみをインデックス化する場合です。
- **インデックス効率を向上させる**: インデックス内のデータ量を削減することで、部分インデックスはインデックスの検索と保守効率を向上させることができます。例えば、ログテーブルで、直近1ヶ月のログのみをインデックス化する場合です。

### 作成文
```sql
CREATE INDEX idx_partial ON table_name (column_name) WHERE condition;
```

## 9. 一意インデックス
### データ構造
一意インデックスのデータ構造は通常のインデックスと同じで、通常はB - ツリーや他の適切なインデックス構造を使用します。その特徴は、インデックスカラム内のすべての値が一意であることを保証することです。

### 模式図
```plaintext
+----+-------+
| ID | Value |
+----+-------+
| 1  |  A    |
| 2  |  B    |
| 3  |  C    |
+----+-------+
```

### 原理
一意インデックスは、データの挿入または更新時に、インデックスカラム内の値が一意であるかどうかをチェックし、インデックスカラム内のすべての値が一意であることを保証します。一意性制約に違反する場合、操作は拒否されます。

### アプリケーションシナリオ
- **主キー制約**: 一意インデックスは、主キー制約を実装するために使用でき、テーブル内の各行に一意の識別子があることを保証します。例えば、ユーザテーブルでユーザIDを主キーとして使用する場合です。
- **一意制約**: あるカラム内の値が一意であることを保証する必要があり、主キーでない場合、一意インデックスを使用することができます。例えば、メールアドレスを一意制約としてメールテーブルに使用する場合です。

### 作成文
```sql
CREATE UNIQUE INDEX idx_unique ON table_name (column_name);
```

# [Leapcell: The Best of Serverless Web Hosting](https://leapcell.io/)

最後に、ウェブサービスをデプロイするのに最適なプラットフォームをお勧めします：**[Leapcell](https://leapcell.io/)**

[![brandpic7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4075813/a49ee26e-bc43-49a7-b587-c7964282ca96.png)](https://leapcell.io/)


### 🚀 好きな言語で構築
JavaScript、Python、Go、またはRustで簡単に開発できます。  

### 🌍 無料で無制限のプロジェクトをデプロイ
使用した分だけ支払います — リクエストがなければ、料金はかかりません。  

### ⚡ 使った分だけ支払い、隠されたコストはありません
アイドル料金はなく、シームレスなスケーラビリティを実現します。  

[![Frame3-withpadding2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4075813/3a4dac43-67db-4e08-a3d1-6795093d2645.png)](https://leapcell.io/)


[📖 ドキュメントを参照する](https://docs.leapcell.io/)  

🔹 Twitterでフォロー: [@LeapcellHQ](https://x.com/LeapcellHQ)