PostgreSQLの実行計画は、SQL文の前にexplain
を置く事によって取得できます。しかし、1つ重要な制限事項があります。
バインドパラメータを使ったSQL文
($1
や$2
など)においては、この方法では実行計画を取得できません。まず最初にプリペアド
ステートメントとして宣言する必要があるのです。
PREPARE stmt(int) AS SELECT $1
PostgreSQLでは、バインドパラメータに「$n
」を使用する事に
注意しましょう。使用しているデータベース抽象化層によってはこれを隠してしまう事があるので、SQL標準で定義されているように、
クエスチョンマークを使いましょう。
プリペアドステートメントは以下のように実行します。
EXPLAIN EXECUTE stmt(1)
PostgreSQL 9.2以降では、実行時まで実行計画の作成は先送りされるので、バインドパラメータに関しては実際の値を考慮に入れます。バインドパラメータの実際の値を考慮しない実行計画を取得するため、PostgreSQL 16ではexplain
のgeneric_plan
オプションが導入されました。
注記
バインドパラメータなしの文に関しては、もっと単純な説明になります。
EXPLAIN SELECT 1
この時、オプティマイザはクエリの計画時に実際の値をいつも考慮に入れます。
実行計画の出力は次のようになります。
QUERY PLAN
------------------------------------------
Result (cost=0.00..0.01 rows=1 width=0)
出力は、この本で取り上げているOracleの実行計画とほぼ同じです。 処理名(「Result」)、関連するコスト値、行数の見積、行の長さです。
PostgreSQLは2つのコスト値を表示するのに注意しましょう。 1つ目は初期処理のコスト、2つ目は全行を取り出し終えるまでの処理の全コストです。 Oracleの実行計画では、2つ目の値しか表示されていません。
PostgreSQLのexplain
コマンドには、analyze
、buffers
、settings
といった非常に便利なものを含む多くのオプションがあります。
協力してください
この記事が気に入ったら、私の書いた本「SQLパフォーマンス詳解」や私によるトレーニングもきっと気にいるはず。
analyze
オプションを有効にすると、実行計画が作成されるだけでなく文の実行も行われます。これはつまり、delete
文の情報を表示したい時に実際に削除が実行されてしまうといったように、情報を表示したい文を実行する際の副作用が発生しまうということです。このような副作用の影響が残らないようにしたい場合は、explain
をトランザクションに入れて、実行後にロールバックすることもできます。
警告
explain analyze
は、対象が
insert
やupdate
、delete
の場合でも文を実際に実行してしまいます。
実際に文を実行することで、各処理における実行時間や、生成される行の実際の数といった実行時の情報を収集できます。またbuffers
オプションは、アクセスされるデータベースブロック数を数えます。
最後にsettings
オプションは、デフォルト値から変わっている設定を表示します。
BEGIN
EXPLAIN (ANALYZE, BUFFERS, SETTINGS) EXECUTE stmt(1)
QUERY PLAN
--------------------------------------------------
Result (cost=0.00..0.01 rows=1 width=4)
(actual time=0.001..0.002 rows=1 loops=1)
Settings: random_page_cost = '1.1'
Planning Time: 0.032 ms
Execution Time: 0.078 ms
ROLLBACK
この表示はページに合うようにフォーマットしてあります。実際には「actual」の値は見積値と同じ行に表示されます。
行数は見積と実際の値、どちらの部分にも表示されています。 これによって、カーディナリティの見積のおかしな部分をすぐに見つけられます。
最後に大事な事ですが、プリペアドステートメントはクローズしておきましょう。
DEALLOCATE stmt