PostgreSQL 18(2025年9月リリース)では、EXPLAIN ANALYZEにいくつかの改善が加えられました。そこで、新たに追加された機能を中心に、実行計画の読み方をまとめてみました。
こちらで様々なバージョンを試せます。
PostgreSQL 18でのEXPLAIN ANALYZEの改善点
バッファ使用統計がデフォルトで表示
PostgreSQL 18では、BUFFERSオプションを指定しなくても、EXPLAIN ANALYZEを実行するとバッファ使用統計が自動的に表示されます。
EXPLAIN ANALYZE SELECT * FROM users WHERE id = 1;
実行結果(PostgreSQL 18):
Index Scan using users_pkey on users (cost=0.29..8.30 rows=1 width=36)
(actual time=0.045..0.046 rows=1 loops=1)
Index Cond: (id = 1)
Buffers: shared hit=4
Index Lookups: 1
Planning Time: 0.123 ms
Execution Time: 0.046 ms
以前のバージョンではBUFFERSオプションを明示的に指定する必要がありましたが、PostgreSQL 18ではデフォルトで以下の情報が表示されます:
- shared hit: 共有バッファから読み込まれたページ数
- shared read: ディスクから読み込まれたページ数
- shared dirtied: 変更されたページ数
- shared written: 書き込まれたページ数
これにより、キャッシュの利用状況を簡単に確認できるようになりました。
VERBOSEオプション
VERBOSEオプションを付けると、各ノードの出力列リストの表示や、テーブル・関数名のスキーマ修飾など、プランの詳細表示が増えます。
EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM users WHERE id = 1;
なお、WALに関する統計を確認したい場合はEXPLAIN (WAL)を利用します。PostgreSQL 18ではEXPLAIN (WAL)の出力が改善されています。
インデックス探索回数の表示
PostgreSQL 18では、インデックススキャン系ノードでインデックス探索回数(Index Lookups / Index Searches、出力名はノードにより異なります)が表示され、同じインデックスを何回探索したかが読み取りやすくなりました。
Index Scan using users_pkey on users
Index Cond: (id = 1)
Index Lookups: 1
これにより、インデックスの使用効率を評価しやすくなりました。特に複雑なクエリで、インデックスが期待通りに機能しているかを確認する際に役立ちます。
基本的な使い方
EXPLAIN ANALYZE SELECT * FROM users WHERE id = 1;
EXPLAINだけでも実行計画は見られます
オプション:
-
BUFFERS: PostgreSQL 18ではデフォルトで表示されるが、明示的に指定することも可能 -
VERBOSE: 各ノードの出力列リストなど、より詳細な情報を表示 -
WAL: WALに関する統計情報を表示 -
SETTINGS: クエリプランナーが使用した設定を表示 -
FORMAT: JSONやYAML、XML形式で出力(FORMAT JSONなど)
バージョン確認:
SELECT version();
-- PostgreSQL 18.1 on x86_64-pc-linux-gnu など
PostgreSQL 18で確認できる実行計画の読み方
実行計画は木構造(ツリー構造)で表示されます。PostgreSQL 18では、バッファ統計やインデックスルックアップ回数などがデフォルトで表示されるため、より詳細な分析が可能です。
QUERY PLAN
────────────────────────────────────────────────────────────────────────────
Seq Scan on users (cost=0.00..22.50 rows=1000 width=36)
(actual time=0.123..12.456 rows=1000 loops=1)
Filter: (id = 1)
Rows Removed by Filter: 999
Buffers: shared hit=5 read=3
Planning Time: 0.123 ms
Execution Time: 12.456 ms
PostgreSQL 18で新たに表示される項目:
-
Buffers: デフォルト表示。
shared hit(キャッシュヒット)、shared read(ディスク読み込み)などでI/O状況を確認可能 - Index Lookups / Index Searches: インデックススキャンで実行された探索の回数(出力名はノードにより異なります)
これらにより、I/Oの効率やインデックスの使用状況を容易に把握できるようになりました。
実行計画で確認する
Skip Scansによる実行計画の変化
PostgreSQL 18では、Skip Scansが追加され、マルチカラムB-treeインデックスの先頭列を指定しなくてもインデックスを効率的に使用できるようになりました。
従来の実行計画(PostgreSQL 17以前):
CREATE INDEX idx_users_status_created ON users (status, created_at);
EXPLAIN ANALYZE
SELECT * FROM users WHERE created_at > '2024-01-01';
Seq Scan on users (cost=0.00..25000.00 rows=50000 width=36)
(actual time=0.123..500.456 rows=50000 loops=1)
Filter: (created_at > '2024-01-01'::date)
Rows Removed by Filter: 50000
Buffers: shared read=1000
Planning Time: 0.123 ms
Execution Time: 500.456 ms
PostgreSQL 18での実行計画:
Index Scan using idx_users_status_created on users
(cost=0.29..1000.30 rows=50000 width=36)
(actual time=0.045..50.234 rows=50000 loops=1)
Index Cond: (created_at > '2024-01-01'::date)
Buffers: shared hit=200 read=50
Index Lookups: 500
Planning Time: 0.123 ms
Execution Time: 50.234 ms
実行計画上は、インデックス探索回数(Index Searches等)が増える形で挙動を読み取れることがあります。また、Buffersでキャッシュの利用状況も確認できます。
OR/IN句の最適化を実行計画で確認
PostgreSQL 18では、条件によってはOR条件を配列(ANY)形式に変換してインデックス処理を効率化する最適化が入りました(適用可否はクエリ形状と統計に依存します)。実行計画で確認してみましょう:
CREATE INDEX idx_users_status ON users (status);
EXPLAIN ANALYZE
SELECT * FROM users WHERE status IN ('active', 'pending', 'suspended');
PostgreSQL 18では、BuffersやIndex Lookups / Index Searchesで実際のI/O状況を確認できます。実行計画の選択や性能は、データ分布やクエリの特性によって異なります。最適化が適用された場合、実行計画で配列操作(ANY)が使用されていることが確認できる場合があります。
非同期I/O(AIO)による実行時間の改善
非同期I/O(AIO) が導入され、シーケンシャルスキャンなどのI/O操作が高速化されることがあります。実行計画の表示自体は変わりませんが、actual timeで実際の実行時間の改善を確認できます:
EXPLAIN ANALYZE
SELECT * FROM large_table WHERE created_at > '2024-01-01';
実行計画の例:
Seq Scan on large_table (cost=0.00..50000.00 rows=1000000 width=36)
(actual time=0.123..2000.234 rows=1000000 loops=1)
Filter: (created_at > '2025-01-01'::date)
Buffers: shared read=20000
Execution Time: 2000.234 ms
AIOによる性能向上は、データサイズ、I/Oサブシステム、キャッシュの状態など、様々な要因に依存します。特定のワークロードでは大幅な改善が見られる場合もありますが、環境によって効果は異なります。
クラウド環境とモダンなアーキテクチャでの実行計画
AWS RDS、GCP Cloud SQL、Azure Database for PostgreSQLなどのマネージドサービスでも、EXPLAIN ANALYZEは同じように使用できます。モダンなアプリケーションアーキテクチャでの活用ポイント:
-
リードレプリカ:
ANALYZEオプションが使えない場合があるため、EXPLAINのみで実行計画を確認 -
パフォーマンスモニタリングツールとの連携:
AWS RDS Performance Insights、GCP Cloud SQL Insightsなどと組み合わせて、実行計画と実際のパフォーマンスを関連付けて分析 -
マイクロサービス環境: 複数のデータベースに分散している場合でも、各サービスで
EXPLAIN ANALYZEを使用してボトルネックを特定 -
コンテナ環境: 同じように
EXPLAIN ANALYZEが使用可能
実践的な分析例
バッファ統計を活用したI/O分析
PostgreSQL 18では、バッファ統計がデフォルトで表示されるため、キャッシュの効率を簡単に確認できます:
EXPLAIN ANALYZE
SELECT * FROM large_table WHERE status = 'active';
実行計画:
Seq Scan on large_table (cost=0.00..25000.00 rows=100000 width=36)
(actual time=0.123..500.456 rows=100000 loops=1)
Filter: (status = 'active')
Rows Removed by Filter: 900000
Buffers: shared hit=500 read=4500
Planning Time: 0.123 ms
Execution Time: 500.456 ms
Buffers: shared hit=500 read=4500から、5000ページ中500ページがキャッシュから読み込まれ、4500ページがディスクから読み込まれたことがわかります。キャッシュヒット率が低い場合は、インデックスの追加やクエリの改善を検討します。
Index Lookupsでインデックスの効率を評価
PostgreSQL 18では、インデックススキャンでルックアップの回数が表示されます:
EXPLAIN ANALYZE
SELECT * FROM users WHERE email IN ('user1@example.com', 'user2@example.com', ...);
実行計画:
Index Scan using idx_users_email on users
(cost=0.29..100.30 rows=100 width=36)
(actual time=0.045..5.234 rows=100 loops=1)
Index Cond: (email = ANY ('{user1@example.com,user2@example.com,...}'::text[]))
Buffers: shared hit=150
Index Lookups: 100
Planning Time: 0.123 ms
Execution Time: 5.234 ms
Index Lookups: 100から、100回のインデックス探索が実行されたことがわかります(出力名はノードにより「Index Searches」と表示される場合もあります)。この値が大きい場合は、クエリの見直しやバッチ処理の検討が必要です。
参考
プレスキットにまとめてくれています。
