Featured image of post Web開発者のためのPostgreSQLパフォーマンスチューニング超入門 Featured image of post Web開発者のためのPostgreSQLパフォーマンスチューニング超入門

Web開発者のためのPostgreSQLパフォーマンスチューニング超入門

インデックス設計の基本から、スロークエリ特定に便利なEXPLAINコマンドの見方まで。

PostgreSQLを使用したアプリケーションが遅くなる最大の原因は、データベースアクセス時の非効率なクエリです。テーブル結合時のインデックス利用状況や、EXPLAIN ANALYZE コマンドでボトルネックを特定する方法を学びます。

本記事では、PostgreSQLのパフォーマンス向上を目指すウェブ開発者のために、インデックス設計の基本ルール、実行計画の読み方、および主要なパラメータ調整によるサーバーチューニングについて解説します。


1. 適切なインデックス設計(基本にして最大の対策)

リレーショナルデータベースにおける最大のボトルネックは、HDDやSSDといったストレージからのデータの読み出し(I/O)です。インデックス(索引)を適切に張ることで、全行を探索する「フルスキャン(Seq Scan)」を回避し、目的のデータへ直接アクセスさせます。

1) B-treeインデックスの原則

PostgreSQLのデフォルトであるB-treeインデックスは、以下の条件で有効に機能します。

  • WHERE 句での完全一致や範囲比較(=, <, >, BETWEEN 等)
  • ORDER BY による並べ替え
  • JOIN の結合キー

2) 複合インデックスの「順序」ルール

2つ以上のカラムを組み合わせた複合インデックス(Composite Index)を設計する際は、**「左側のカラムから順番に評価される」**というルールに注意する必要があります。

-- インデックス定義
CREATE INDEX idx_users_status_created ON users (status, created_at);

-- ◯ インデックスが効くクエリ(左側のstatusを指定しているため)
SELECT * FROM users WHERE status = 'active' AND created_at > '2026-01-01';
SELECT * FROM users WHERE status = 'active';

-- ✕ インデックスがほとんど効かないクエリ(先頭カラムのstatusが指定されていないため)
SELECT * FROM users WHERE created_at > '2026-01-01';

2. EXPLAIN ANALYZE で実行計画を解読する

クエリが遅いと感じたら、必ずクエリの先頭に EXPLAIN ANALYZE を付与して実行し、PostgreSQLがどのようにデータを探索しているかを確認します。

EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 45291;

実行計画で見るべき重要項目

出力結果に含まれる以下のキーワードに注目します。

  1. Seq Scan(シーケンシャルスキャン): テーブルの全行を先頭から順に走査していることを意味します。データ量が多いテーブルでこれが検出された場合、インデックスの不足を疑う必要があります。
  2. Index Scan / Index Only Scan: インデックスが適用されていることを示します。特に Index Only Scan は、必要なデータがインデックス内にすべて含まれており、本テーブルのディスク領域を参照しなかったため、最も高速です。
  3. Actual Time: 実際に処理にかかったミリ秒数。クエリ中のどのステップ(結合や集約)が処理時間を引き延ばしているか特定できます。

3. 代表的なメモリ設定パラメータの最適化

クラウドのマネージドデータベース(AWS RDSやCloudflare D1、Supabase等)やセルフホスト環境において、初期設定のままだとマシンスペック(メモリ容量)を活かしきれないことがよくあります。postgresql.conf 内の以下の項目をチューニングします。

  • shared_buffers: データベースがデータブロックをキャッシュするために使用するメモリサイズ。実メモリの 25% 程度を目安に設定します。
  • work_mem: ソート処理(ORDER BY)やハッシュ結合(JOIN)を行う際に、1クエリの内部処理で使用可能なメモリ量。これが小さすぎると、処理がディスク上のテンポラリファイルに書き出され、極端に遅くなります。4MB〜16MB程度に増やします(クエリ並行数との兼ね合いで調整)。
  • maintenance_work_mem: インデックスの作成(CREATE INDEX)や VACUUM などの管理タスクで使われるメモリ。128MB〜512MB程度と大きめに確保します。

4. まとめ:計測ベースのチューニング

パフォーマンスチューニングで最も重要なのは、「推測するな、計測せよ」という原則です。インデックスを追加した後は、必ず EXPLAIN ANALYZE を再実行し、実際にコストと実行時間が削減されているか確認する習慣をつけましょう。