無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

52.4. 外部データラッパのクエリプラン作成

FDWコールバック関数の GetForeignRelSize GetForeignPaths GetForeignPlan PlanForeignModify PostgreSQL プランナの動作と協調しなければなりません。ここでは、これらの関数がすべき事に関するいくつかの注意事項を述べます。

root baserel に含まれる情報は、外部テーブルから取得する必要のある情報の量(とそれによるコスト)を削減するために使用できます。 baserel->baserestrictinfo は、取得される行をフィルタリングする制約条件( WHERE 句)を含んでいるため、特に興味深いものです。(コアのエグゼキュータが代わりにそれらをチェックできるので、FDW自身がこれらの制約を適用しなければならないわけではありません。) baserel->reltargetlist はどのカラムが取得される必要があるかを決定するのに使用できます。ただし、このリストは ForeignScan プランノードから出力すべきカラムしか含んでおらず、条件検査には必要だがクエリからは出力されないカラムは含まないことに注意してください。

様々なプライベートフィールドがFDWのプラン作成関数で情報を格納する目的で利用できます。 一般的に、プラン作成の最後に回収できるように、FDW固有フィールドに格納するものは全てpallocで確保すべきです。

baserel->fdw_private は、 void ポインタで、FDWのプラン作成関数で特定の外部テーブルに関する情報を格納する目的で利用できます。 コアプランナは、 baserel ノードが作成されるときにNULLで初期化するときを除いて、このフィールドに一切に触れません。 このフィールドは、 GetForeignRelSize から GetForeignPaths GetForeignPaths から GetForeignPlan といったように情報を順次伝えるの便利で、結果として再計算を省くことができます。

GetForeignPaths では、 ForeignPath ノードの fdw_private フィールドに固有情報を格納することで、異なるアクセスパスを区別できます。 fdw_private List ポインタとして宣言されていますが、コアプランナがこのフィールドを操作することはないため、実際にはなんでも格納できます。 しかし、バックエンドのデバッグサポート機能を利用できるように nodeToString でダンプ出来る形式を使うのが最良の手法です。

GetForeignPlan では、選択された ForeignPath ノードの fdw_private フィールドを調べて、 ForeignScan プランノード内に格納されプラン実行時に利用可能な fdw_exprs fdw_private の二つのリストを生成することができます。 これらは両方とも copyObject がコピーできる形式でなければなりません。 fdw_private リストにはこれ以外に制約はなく、コアバックエンドによって解釈されることはありません。 fdw_exprs リストがNILでない場合は、クエリ実行時に実行されることを意図した式ツリーが含まれていることが期待されます。 これらのツリーは、完全に実行可能な状態にするためにプランナによる後処理を受けます。

GetForeignPlan では、一般的に渡されたターゲットリストはそのままプランノードにコピーできます。 渡されたscan_clausesリストは baserel->baserestrictinfo と同じ句を含みますが、実行効率のよい別の順番に並べ替えることもできます。 FDWにできるのが RestrictInfo ノードをscan_clausesリストから( extract_actual_clauses を使って)抜き出して、全ての句をプランノードのqualリストに入れるだけ、といった単純なケースでは、全ての句は実行時にエグゼキュータによってチェックされます。 より複雑なFDWは内部で一部の句をチェックできるかもしれませんが、そのような場合には、エグゼキュータが再チェックのために時間を無駄にしないように、それらの句はプランノードのqualリストから削除できます。

たとえば、ローカル側で評価された sub_expression の値があればリモートサーバ側で実行出来るとFDWが判断するような、 foreign_variable = sub_expression といった形式の条件句をFDWが識別するかもしれません。 パスのコスト見積もりに影響するので、そのような句の実際の識別は GetForeignPaths でなされるべきです。 おそらく、そのパスの fdw_private フィールドは識別された句の RestrictInfo ノードをさすポインタを含むでしょう。 そして、 GetForeignPlan はその句をscan_clausesから取り除き、実行可能な形式にほぐされることを保障するために sub_expression fdw_exprs に追加するでしょう。 また、おそらく、実行時に何をすべきかをプラン実行関数に伝えるためにプランノードの fdw_private フィールドに制御情報を入れるでしょう。 リモートサーバに送られたクエリは、実行時に fdw_exprs 式ツリーを評価して得られた値をパラメータ値とする WHERE foreign_variable = $1 のようなものを伴うでしょう。

FDWはそのテーブルの条件句のみに依存するパスを常に少なくとも一つは生成すべきです。結合クエリでは、例えば foreign_variable = local_variable といった結合句に依存するパス(群)を生成することもできます。 そのような句は baserel->baserestrictinfo には見つからず、リレーションの結合リストにあるはずです。 そのような句を使用するパスは "パラメータ化されたパス" と呼ばれます。 このようなパスでは、選択された結合句(群)で使用されているリレーション(群)を param_info の適合する値から特定しなければなりません;その値を計算するには get_baserel_parampathinfo を使用します。 GetForeignPlan では、結合句の local_variable 部分が fdw_exprs に追加され、実行時には通常の条件句と同じように動作します。

UPDATE DELETE のプランを生成しているとき、 PlanForeignModify は、事前にスキャンプラン生成関数で作られた baserel->fdw_private データを使うために、その外部テーブルのための RelOptInfo 構造体を検索することができます。 しかしながら、 INSERT では対象テーブルはスキャンされないので対応する RelOptInfo は存在しません。 PlanForeignModify から返される List には、 ForeignScan プランノードの fdw_private リストと同様に、 copyObject がコピーの仕方を知っている構造体しか保持してはいけないという制約があります。

同時更新をサポートする外部データソースに対する UPDATE DELETE では、 ForeignScan 操作はFDWがフェッチする行を、できれば SELECT FOR UPDATE に相当するものを用いてロックすることが推奨されています。 また、外部テーブルが SELECT FOR UPDATE/SHARE で参照される場合に、FDWは取り出し時に行をロックすることを選択することもできます。そうでない場合、外部テーブルに関する限り FOR UPDATE FOR SHARE といったオプションは基本的に何もしません。 この挙動は、習慣的に行ロックは可能な限り遅延されるという、ローカルテーブルに対する操作と全く異なるセマンティクスをもたらすかもしれません。 ローカルで適用される制約や結合条件で除外されるリモート行でさえもロックされるかもしれません。 しかしながら、ローカルセマンティクスと完全に一致させることは、各行について追加のリモートアクセスが必要となるうえ、外部データソースが提供するロックセマンティクスに依存するためおそらく不可能でしょう。


powered by SEO.CUG.NET