与えられた文に対して、PostgreSQLプランナが生成する実行計画を表示します。 実行計画は、問い合わせ文が参照するテーブル(複数の場合もある)をスキャンする方法(単純なシーケンススキャン、インデックススキャンなど)、複数のテーブルを参照する場合に、各テーブルから取り出した行を結合するために使用する結合アルゴリズムを示すものです。
表示内容の中でも、最も重要なのは、文の実行にかかるコストの見積もりです。 これは、プランナが文の実行にかかる時間(ディスクページ抽出の単位で計測)を推測したものです。 具体的には、2つの数が表示されます。 1つは最初の行が返されるまでのスタートアップ時間、もう1つは全ての行が返されるまでの合計時間です。 ほとんどの問い合わせにとって問題となるのは合計時間の方ですが、EXISTS副問い合わせなどのコンテキストでは、プランナは合計時間が最も短くなるプランよりも、スタートアップ時間が最も短くなるプランを選びます(エクゼキュータは行を1つ取得した後に停止するからです)。 さらに、LIMIT句を使って問い合わせが返す行数を制限する場合、プランナは実際にはどの計画が一番低コストになるかを概算するため、全体を処理した場合のコストの間で適切な補間を行います。
ANALYZEオプションを付けると、計画を作るだけでなく、問い合わせ文が実際に実行されます。 この場合は、各計画ノードで費された総経過時間(ミリ秒単位)と実際に返される行数も表示されます。 プランナの推測と実際の値がどの程度近くなるかを確認できるという点で、このオプションは有用です。
重要項目: ANALYZEを使用した場合は、文が実際に実行されることを忘れないでください。 EXPLAINはSELECTが返す出力をまったく表示しませんが、文に伴う副作用は通常通り発生します。 INSERT、UPDATE、DELETE、EXECUTE文に対して、データに影響を与えないようにEXPLAIN ANALYZEを実行したい場合は、以下の方法を使用してください。
BEGIN; EXPLAIN ANALYZE ...; ROLLBACK;
コマンドを実行し、実際の稼働時間を表示します。
要約だけではなく計画ツリーの内部表現を全て表示します。 通常、このオプションが有用なのは、デバッグ時のみです。 VERBOSEの出力は、explain_pretty_print設定パラメータの設定次第で印刷に適した形にすることができます。
実行計画の表示対象となる、SELECT、INSERT、UPDATE、DELETE、EXECUTE、DECLAREのいずれかの文です。
PostgreSQLのオプティマイザにおけるコスト情報の使用に関する文書は多くありません。 詳しい情報については、項13.1を参照してください。
PostgreSQL問い合わせプランナが十分な情報を使って問合せを最適化できるようにするには、ANALYZE文を実行して、テーブル内のデータ分布についての統計情報を記録しておかなければいけません。 これを行わない場合(あるいは、前回ANALYZEを実行した後、テーブル内のデータの統計的分布が大幅に変わった時)、推定コストが問い合わせの実際の属性とは一致しない恐れが高く、その結果、不適切な問い合わせ計画が選択される可能性があります。
遺伝的問い合わせ最適化(GEQO)は不規則的に実行計画を試験します。
したがって、テーブル数が遺伝的問い合わせ最適化の使用が始まるgeqo_threshold
を超えると、実行計画は文が実行する度に変わることになります。
PostgreSQL 7.3より前のバージョンでは、問い合わせ計画はNOTICEメッセージという形式で通知されていました。 現在では、問い合わせ計画は問い合わせ結果として(単一のテキスト列からなるテーブルの形式で)表示されます。
integer列を1つ持ち、10000行が存在するテーブルに対して、単純な問い合わせを行った場合の問い合わせ計画を表示します。
EXPLAIN SELECT * FROM foo; QUERY PLAN --------------------------------------------------------- Seq Scan on foo (cost=0.00..155.00 rows=10000 width=4) (1 row)
インデックスが存在し、問い合わせのWHERE条件でインデックスを利用できる場合、EXPLAINは異なる計画を表示する可能性があります。
EXPLAIN SELECT * FROM foo WHERE i = 4; QUERY PLAN -------------------------------------------------------------- Index Scan using fi on foo (cost=0.00..5.98 rows=1 width=4) Index Cond: (i = 4) (2 rows)
次に、集約関数を使用した問い合わせに対する問い合わせ計画の例を示します。
EXPLAIN SELECT sum(i) FROM foo WHERE i < 10; QUERY PLAN --------------------------------------------------------------------- Aggregate (cost=23.93..23.93 rows=1 width=4) -> Index Scan using fi on foo (cost=0.00..23.92 rows=6 width=4) Index Cond: (i < 10) (3 rows)
以下は、EXPLAIN EXECUTEによって準備された文に対する実行計画を表示する例です。
PREPARE query(int, int) AS SELECT sum(bar) FROM test WHERE id > $1 AND id < $2 GROUP BY foo; EXPLAIN ANALYZE EXECUTE query(100, 200); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------- HashAggregate (cost=39.53..39.53 rows=1 width=8) (actual time=0.66..0.67 rows=7 loops=1) -> Index Scan using test_pkey on test (cost=0.00..32.97 rows=1311 width=8) (actual time=0.05..0.39 rows=99 loops=1) Index Cond: ((id > $1) AND (id < $2)) Total runtime: 0.85 msec (4 rows)
もちろん、ここで示した具体的な数値は対象とするテーブルの実際の中身によって変わります。 また、この数値や選択された問い合わせ戦略は、プランナの改良のため、PostgreSQLのリリース間で異なることもありますので注意してください。 さらに、ANALYZEコマンドは、データの統計情報を推定する際にランダムなサンプリングを行うため、実際のテーブル内の分布が変わっていなくても、新たにANALYZEを実行すると推定コストが変わることがあります。