PostgreSQL 9.1.1文書
前のページ | 巻戻し |  | 早送り | 次のページ

# EXPLAIN

## 名前

EXPLAIN -- 問い合わせ文の実行計画を表示する

## 概要

    EXPLAIN [ ( option [, ...] ) ] statement
    EXPLAIN [ ANALYZE ] [ VERBOSE ] statement

    ここでoptionは以下のいずれかを取ることができます。

        ANALYZE [ boolean ]
        VERBOSE [ boolean ]
        COSTS [ boolean ]
        BUFFERS [ boolean ]
        FORMAT { TEXT | XML | JSON | YAML }

## 説明

与えられた文に対して、PostgreSQLプランナが生成する実行計画を表示します。 実行計画は、問い合わせ文が参照するテーブル（複数の場合もある）をスキャンする方法（単純なシーケンススキャン、インデックススキャンなど）、複数のテーブルを参照する場合に、各テーブルから取り出した行を結合するために使用する結合アルゴリズムを示すものです。

表示内容の中でも、最も重要なのは、文の実行にかかるコストの見積もりです。 これは、プランナが文の実行にかかる時間（ディスクページ抽出の単位で計測）を推測したものです。 具体的には、2つの数が表示されます。 1つは最初の行が返されるまでのスタートアップ時間、もう1つは全ての行が返されるまでの合計時間です。 ほとんどの問い合わせにとって問題となるのは合計時間の方ですが、`EXISTS`副問い合わせなどのコンテキストでは、プランナは合計時間が最も短くなるプランよりも、スタートアップ時間が最も短くなるプランを選びます（エクゼキュータは行を1つ取得した後に停止するからです）。 さらに、`LIMIT`句を使って問い合わせが返す行数を制限する場合、プランナは実際にはどの計画が一番低コストになるかを概算するため、全体を処理した場合のコストの間で適切な補間を行います。

`ANALYZE`オプションを付けると、計画を作るだけでなく、問い合わせ文が実際に実行されます。 この場合は、各計画ノードで費された総経過時間（ミリ秒単位）と実際に返される行数も表示されます。 プランナの推測と実際の値がどの程度近くなるかを確認できるという点で、このオプションは有用です。

> 重要項目: `ANALYZE`を使用した場合は、文が実際に実行されることを忘れないでください。 `EXPLAIN`は`SELECT`が返す出力をまったく表示しませんが、文に伴う副作用は通常通り発生します。 `INSERT`、`UPDATE`、`DELETE`、`CREATE TABLE AS`、`EXECUTE`文に対して、データに影響を与えないように`EXPLAIN ANALYZE`を実行したい場合は、以下の方法を使用してください。

>     BEGIN;
>     EXPLAIN ANALYZE ...;
>     ROLLBACK;

`ANALYZE`および`VERBOSE`オプションのみが、この順序でのみ、オプションリストを括弧で括ることなく、指定可能です。 PostgreSQL 9.0より前までは、括弧がない構文のみがサポートされていました。 すべての新しいオプションは括弧付き構文のみでサポートされることを想定しています。

## パラメータ

`ANALYZE`

  コマンドを実行し、実際の稼働時間を表示します。 このパラメータのデフォルトは`FALSE`です。

`VERBOSE`

  計画についての追加情報を出力します。 具体的に言うと、計画ツリー、スキーマ修飾テーブル、関数名内の各ノードに対して出力列リストを含めます。 常に範囲テーブルの別名を付けて式内の変数を命名し、また常に統計情報が表示される各トリガの名前を出力します。 このパラメータのデフォルトは`FALSE`です。

`COSTS`

  各計画ノードの推定起動コストと総コスト、さらに推定行数と各行の推定幅に関する情報を含めます。 このパラメータのデフォルトは`TRUE`です。

`BUFFERS`

  バッファの使用状況に関する情報を含めます。 具体的には、共有ブロックのヒット数、読み取り数、書き出し数、ローカルブロックのヒット数、読み取り数、書き出し数、一時ブロックの読み取り数、書き出し数が含められます。 共有ブロック、ローカルブロック、一時ブロックにはそれぞれテーブルとインデックス、一時テーブルと一時インデックス、ソートで使用されるディスクブロックと作成された計画が存在します。 上位レベルのノードで表示されるブロック数には、その子ノードすべてで使用されるブロックが含まれます。 テキスト形式では、非ゼロの値のみが出力されます。 このパラメータは`ANALYZE`パラメータといっしょにのみ使用することができます。 デフォルトは`FALSE`です。

`FORMAT`

  出力形式を指定します。 TEXT、XML、JSON、YAMLを指定可能です。 TEXT以外の出力にはTEXT出力と同じ情報が含まれていますが、プログラムによる解析がより容易になります。 このパラメータのデフォルトは`TEXT`です。

`boolean`

  選択したオプションを有効とするか無効とするかを指定します。 オプションを有効にするためには`TRUE`、`ON`、`1`のいずれかを書きます。 無効にするには`FALSE`、`OFF`、 `0`のいずれかを書きます。 `boolean`値は省略可能です。 省略時は`TRUE`と仮定されます。

`statement`

  実行計画の表示対象となる、`SELECT`、`INSERT`、`UPDATE`、`DELETE`、`VALUES`、`EXECUTE`、`DECLARE`、`CREATE TABLE AS`のいずれかの文です。

## 注釈

PostgreSQLのオプティマイザにおけるコスト情報の使用に関する文書は多くありません。 詳しい情報については、項14.1を参照してください。

PostgreSQL問い合わせプランナが十分な情報を使って問合せを最適化できるようにするには、ANALYZE文を実行して、テーブル内のデータ分布についての統計情報を記録しておかなければいけません。 これを行わない場合（あるいは、前回`ANALYZE`を実行した後、テーブル内のデータの統計的分布が大幅に変わった時）、推定コストが問い合わせの実際の特性とは一致しない恐れが高く、その結果、不適切な問い合わせ計画が選択される可能性があります。

実行計画内の各ノードの実行時コストを測定するために、現在の`EXPLAIN ANALYZE`実装は、問い合わせ実行に対し、考え得る特性のオーバーヘッドを加えます。 この結果、ある問い合わせについての`EXPLAIN ANALYZE`実行が、普通に問い合わせを実行した場合より非常に時間がかかることがあります。 このオーバーヘッドの量は問い合わせの性質に依存します。

## 例

`integer`列を1つ持ち、10000行が存在するテーブルに対して、単純な問い合わせを行った場合の問い合わせ計画を表示します。

    EXPLAIN SELECT * FROM foo;

                           QUERY PLAN
    ---------------------------------------------------------
     Seq Scan on foo  (cost=0.00..155.00 rows=10000 width=4)
    (1 row)

以下は同じ問い合わせをJSON形式で出力したものです。

    EXPLAIN (FORMAT JSON) SELECT * FROM foo;
               QUERY PLAN
    --------------------------------
     [                             +
       {                           +
         "Plan": {                 +
           "Node Type": "Seq Scan",+
           "Relation Name": "foo", +
           "Alias": "foo",         +
           "Startup Cost": 0.00,   +
           "Total Cost": 155.00,   +
           "Plan Rows": 10000,     +
           "Plan 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)

以下は同じ問い合わせをYAML出力で表したものです。

    EXPLAIN (FORMAT YAML) SELECT * FROM foo WHERE i='4';
              QUERY PLAN
    -------------------------------
     - Plan:                      +
         Node Type: "Index Scan"  +
         Scan Direction: "Forward"+
         Index Name: "fi"         +
         Relation Name: "foo"     +
         Alias: "foo"             +
         Startup Cost: 0.00       +
         Total Cost: 5.98         +
         Plan Rows: 1             +
         Plan Width: 4            +
         Index Cond: "(i = 4)"
    (1 row)

読者への演習としてXML出力については記載しません。

以下はコストを出力しない同じ計画です。

    EXPLAIN (COSTS FALSE) SELECT * FROM foo WHERE i = 4;

            QUERY PLAN
    ----------------------------
     Index Scan using fi on foo
       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.661..0.672 rows=7 loops=1)
       ->  Index Scan using test_pkey on test  (cost=0.00..32.97 rows=1311 width=8) (actual time=0.050..0.395 rows=99 loops=1)
             Index Cond: ((id > $1) AND (id < $2))
     Total runtime: 0.851 ms
    (4 rows)

もちろん、ここで示した具体的な数値は対象とするテーブルの実際の中身によって変わります。 また、この数値や選択された問い合わせ戦略は、プランナの改良のため、PostgreSQLのリリース間で異なる可能性がありますので注意してください。 さらに、`ANALYZE`コマンドは、データの統計情報を推定する際にランダムなサンプリングを行うため、実際のテーブル内の分布が変わっていなくても、新たに`ANALYZE`を実行すると推定コストが変わることがあります。

## 互換性

標準SQLでは`EXPLAIN`文は定義されていません。

## 関連項目

ANALYZE

前のページ | ホーム | 次のページ
EXECUTE | 上に戻る | FETCH