PREPARE — 実行する文を準備する
PREPAREname
[ (data_type
[, ...] ) ] ASstatement
PREPARE
はプリペアド文を作成します。
プリペアド文は、性能を最適化するために利用可能なサーバ側オブジェクトです。
PREPARE
文を実行すると、指定された問い合わせの構文解析、書き換えが行われます。
その後、EXECUTE
文が発行された際に、プリペアド文は実行計画が作成され、実行されます。
この作業の分割により構文解析作業が繰り返されることを防止でき、さらに、特定のパラメータ値に合わせた実行計画を提供することができます。
プリペアド文はパラメータ、すなわち文が実行される時に代入される値を取ることができます。
プリペアド文を作成する時には$1
や$2
などを使用して、位置によりパラメータを参照してください。
対応するパラメータのデータ型のリストをオプションで指定することもできます。
パラメータのデータ型の指定がない、または、unknown
と宣言されている場合、型はパラメータが最初に参照される文脈より(可能ならば)推測されます。
文の実行時には、EXECUTE
文内にこれらのパラメータの実際の値を指定します。
詳細はEXECUTEを参照してください。
プリペアド文は現在のデータベースセッションの期間中にのみ保持されます。
セッションが終了すると、プリペアド文は破棄されます。
そのため、再び利用する場合は、再作成する必要があります。
また、これは、1つのプリペアド文を同時実行中の複数のデータベースクライアントから使用することはできないことを意味します。
ただし、各クライアントが個別にプリペアド文を作成することはできます。
プリペアド文を手作業で削除するには、DEALLOCATE
コマンドを使用します。
プリペアド文は潜在的には、単一のセッションで同類の問い合わせを多数実行する場合に、パフォーマンスにおける最大の利益がえられます。 パフォーマンスの違いは、文の書き換えや実行計画が複雑なほど顕著になるでしょう。 例えば、問い合わせに多数のテーブルの結合が含まれている場合や、いくつものルールを適用しなければならない場合などが考えられます。 書き換えおよび実行計画が比較的単純で、実行コストが高い文の場合は、プリペアド文の効果はそれほど現れないでしょう。
name
個々のプリペアド文に与えられる任意の名前です。 この名前は、1つのセッション内で一意でなければいけません。プリペアド文の実行および削除の時に、この名前が使用されます。
data_type
プリペアド文に対するパラメータのデータ型です。
特定のパラメータのデータ型の指定がない、または、unknown
と指定された場合、パラメータが最初に参照される文脈から推測されます。
プリペアド文自体の中でこのパラメータを参照する時は、$1
、$2
などを使用します。
statement
任意のSELECT
、INSERT
、UPDATE
、DELETE
、VALUES
文です。
プリペアド文は、汎用的な計画または独自の計画のいずれかで実行することができます。 汎用的な計画は全実行に渡って同じであるのに対して、独自の計画はその呼出しで与えられたパラメータ値を使った特別な実行のために生成されます。 汎用的な計画の使用は計画のオーバーヘッドを回避しますが、プランナがパラメータ値の知識を使えるので、独自の計画の方がずっと効率よく実行される場合があります。 (もちろん、プリペアド文にパラメータがなければ、これは無意味で、汎用的な計画が常に使われます。)
デフォルト(すなわち、plan_cache_modeがauto
に設定されている場合)では、パラメータのあるプリペアド文に対して、汎用的な計画を使うか独自の計画を使うかを、サーバは自動的に選択します。
これに対する現在の規則は、最初の5回が独自の計画で実行され、その計画の推定コストの平均が計算される、というものです。
それから汎用的な計画が作成され、その推定コストが独自の計画のコストの平均と比較されます。
そのコストが独自の計画のコストの平均よりもそれほど高くなければ、再計画を繰り返すことが望ましいと考えて、その後の実行は汎用的な計画を使います。
plan_cache_mode
をforce_generic_plan
またはforce_custom_plan
に設定して、サーバにそれぞれ汎用的な計画または独自の計画を使うように強制することで、この発見的手法を置き換えることができます。
汎用的な計画の実際のコストが独自の計画のものよりもずっと多い場合でも、汎用的な計画を選べるようになりますので、汎用的な計画のコスト推定が何らかの理由でひどく外れる場合に、この設定は主として有用です。
プリペアド文に対してPostgreSQLが使用する問い合わせ計画を検証するためには、EXPLAIN
、例えば
EXPLAIN EXECUTEstmt_name
(parameter_values
);
を使用してください。
汎用的な計画が使用される場合には、$
というパラメータ記号が含まれ、独自の計画が使用される場合は提供されたパラメータの値で置換されます。
n
問い合わせの実行計画や問い合わせの最適化のためにPostgreSQLが収集する統計に関する詳細は、ANALYZEのドキュメントを参照してください。
プリペアド文の主要な利点は、文の解析処理と計画作成処理の繰り返しを防止することですが、PostgreSQLでは、以前にそのプリペアド文を使用してから、文の中で使用されているデータベースオブジェクトが定義(DDL)の変更を受けたり、プランナの統計が更新されたりした時は常に再解析処理と計画再作成処理を強制します。
また、一度使用してからsearch_pathの値が変わった場合も、文は新しいsearch_path
を使用して再解析されます。
(後者の振る舞いはPostgreSQL 9.3の時に追加されました。)
これらの規則により、プリペアド文の使用は意味的に同じ問い合わせを繰り返し再投入することとほぼ同じになりますが、特に最善の計画が使用している間に変わらずに残る場合、オブジェクトの変更がない場合の性能という利点があります。
意味的な等価性が完全ではない場合の例は、
文が未修飾名によってテーブルを参照し、その後同じ名前のテーブルが新たにsearch_path
内で前に現れるスキーマ内に作成された場合、文の中で使用されるオブジェクトには変更がありませんので、自動再解析は行われません。
しかし他の何らかの変更により強制的に再解析された場合、その後の使用では新しいテーブルが参照されるようになります。
pg_prepared_statements
システムビューを問い合わせることによりセッションで利用可能なプリペアド文をすべて確認することができます。
INSERT
文に対してプリペアド文を作成し、実行します。
PREPARE fooplan (int, text, bool, numeric) AS INSERT INTO foo VALUES($1, $2, $3, $4); EXECUTE fooplan(1, 'Hunter Valley', 't', 200.00);
SELECT
文に対してプリペアド文を作成し、実行します。
PREPARE usrrptplan (int) AS SELECT * FROM users u, logs l WHERE u.usrid=$1 AND u.usrid=l.usrid AND l.date = $2; EXECUTE usrrptplan(1, current_date);
この例では第2パラメータのデータ型が指定されていません。
このため$2
が使用される文脈からデータ型が推測されます。
標準SQLにはPREPARE
文が含まれていますが、埋め込みSQLでの使用に限られています。
また、標準SQLのPREPARE
文では多少異なる構文が使用されます。