概要
この記事は PostgreSQLのインデックス について、内部構造や種類、トレードオフ、最適化手法を直感的に理解している開発者向けに解説。 インデックスの基本、ディスク上でのデータ保存方式、インデックスによるクエリ高速化の仕組みを説明。 インデックス利用時のコスト や注意点、各インデックスタイプの特徴を整理。 B-Tree を中心に、他のインデックスタイプも簡単に紹介。 実際のクエリ例やコマンドも交えて、 実践的な知識 を提供。
PostgreSQLインデックスの内部構造と最適化
- 対象読者 :インデックスの直感的理解はあるが、内部動作やトレードオフ、PostgreSQL固有のインデックス種類・最適化手法を知りたい開発者
- インデックスの役割 :データアクセス高速化のための特別なデータベースオブジェクト
- ディスクから読むデータ量削減
- 主キーやユニークキーなどの制約実現
- インデックス利用の注意点 :クエリがインデックス対象カラム・型に一致しないと効果なし
- インデックスの有効範囲 :一般的にテーブルの15~20%未満を返すクエリで有効
- それ以上はシーケンシャルスキャンが選ばれやすい
- クエリプランナーは統計情報とコストを元に最適戦略を決定
- テーブル構造 :PostgreSQLでは各テーブルが1つ以上のファイル(ヒープ)で管理
- 8KBページ単位で分割
- 行(タプル)は順序なく保存
- インデックスはツリー構造で、インデックスカラムと行位置(ctid)を紐付け
- ctid :各行の物理位置を示す内部フィールド((ページ番号, オフセット)形式)
データ保存とctidの確認
- データディレクトリ の確認:
show data_directory; - テーブルファイルの特定 :
pg_classやpg_databaseテーブルを利用 - ctidの取得 :
select ctid, * from テーブル名;で行の物理位置を確認
インデックスによる高速化の仕組み
- インデックスなしの場合 :全ページ・全行を順次読み込みフィルタリング(シーケンシャルスキャン)
- 大量データではI/Oコストと実行時間が増加
- インデックス追加後 :インデックススキャンにより最小限のページアクセスで目的行に到達
- 実行時間とI/O大幅削減
- インデックスサイズ :インデックス自体もディスク容量を消費
- 大規模テーブルではインデックスサイズがテーブル本体と同等以上になることも
インデックス利用時のコスト
- ディスク容量増加 :インデックスごとに追加ストレージが必要
- バックアップやレプリケーション、リカバリ時間への影響
- 書き込みコスト増加 :UPDATE/INSERT/DELETE時にインデックス更新が発生
- 書き込み性能低下
- クエリプランナー負荷 :インデックス数が多いほど最適化計算が複雑化
- メモリ使用量増加 :共有バッファや作業メモリをインデックスで消費
- 大きなカラムや複雑なインデックスではツリーが深くなり、メモリ消費増加
- メタデータや統計情報、メンテナンス(VACUUM/REINDEX)にもメモリ必要
PostgreSQL標準インデックスタイプ
- B-Treeインデックス
-
汎用性が高く、ほぼすべてのDBMSで採用
-
O(log n)の高速検索・挿入・削除
-
データがRAMを超えても効率的なディスクアクセス
-
PostgreSQLのデフォルトかつ最も一般的なインデックスタイプ
-
主キー・ユニークキー制約にも利用
-
バランス木構造で、全てのリーフノードがルートから同じ距離
-
内部ノードは下位ノードへのポインタ、リーフノードはキーとヒープへのポインタ
-
ノード間の左右リンクにより順方向・逆方向の走査が容易
-
値はリーフノードのみに保存、ツリーのコンパクト化と高速性を実現
-
その他のインデックスタイプ (概要のみ)
- Hashインデックス :等価比較専用、B-Treeより用途限定
- GIN(Generalized Inverted Index) :配列や全文検索向け
- GiST(Generalized Search Tree) :空間データや類似検索向け
- SP-GiST :空間分割型データ向け
- BRIN(Block Range INdex) :大規模・連続データ向け、スペース効率重視
-
拡張による追加インデックス も利用可能
-
インデックス設計のポイント
- インデックス追加前の検討事項
- クエリの返却行数が多い場合は設計見直しやサマリーテーブル利用を検討
- 部分インデックスや複合インデックス、BRINなどの利用でスペース効率化
- インデックスの管理
- 過剰なインデックス追加は逆効果
- 定期的な統計情報の更新やメンテナンス(VACUUM/REINDEX)が重要
まとめ
- インデックスは高速化の切り札 だが、 コストとトレードオフ を理解した設計が必須
- B-Treeインデックス が基本だが、用途に応じて他のタイプも検討
- クエリ内容・データ量・運用要件 に合わせた最適化が重要
- PostgreSQLの内部構造や統計情報 を活用し、効果的なインデックス運用を心がける