★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

40.1. 問い合わせツリーとは

どのようにルールシステムが機能するかを理解するためには、ルールがどのように起動され、その入力と結果は何かを理解しなければなりません。

ルールシステムは問い合わせパーサとプランナの中間に位置します。 ルールシステムは、入力としてパーサの出力、単一の問い合わせツリー、および何らかの特別な情報を持つ問い合わせツリーでもあるユーザ定義の書き換えルールを取り、結果として0個以上の問い合わせツリーを生成します。 ルールシステムの入力と出力は常にパーサ自体でも生成することができるもので、参照する対象は基本的にSQL文として表現できるものです。

では問い合わせツリーとは何でしょうか。 それは、SQL文を構成する個々の部品を別々に記憶した、SQL文の内部表現です。 debug_print_parsedebug_print_rewritten、もしくはdebug_print_plan設定パラメータを設定していれば、サーバログ内で問い合わせツリーを見ることができます。 ルールアクションもpg_rewriteシステムカタログ内に問い合わせツリーとして格納されています。 これはログ出力のように整形されていませんが、まったく同じ情報を持っています。

問い合わせツリーそのものを読むためにはある程度の経験が必要です。 ルールシステムを理解するためには問い合わせツリーのSQL表現で十分ですので、ここではその読み方までは教えません。

本章の問い合わせツリーのSQL表現形式を読む時に必要なのは、問い合わせツリー構造の中に分解された、ある文の部品を識別できることです。 問い合わせツリーには以下の部品があります。

コマンド種類

これはどのコマンド(SELECTINSERTUPDATEDELETE)が構文解析ツリーを作ったかを示す単純な値です。

範囲テーブル

範囲テーブルは問い合わせで使われるリレーションのリストです。 SELECT文ではこれはFROMキーワードの後で与えられるリレーションになります。

範囲テーブルのそれぞれの項目はテーブルもしくはビューを識別し、問い合わせの別の部品ではどんな名前で呼び出されるかを示します。 問い合わせツリーでは範囲テーブルの項目は名前よりも番号で参照されることが多いため、ここではSQL文とは違い、重複する名前があるかということは問題になりません。 これはルールの範囲テーブルがマージされた後に起こる可能性があります。 本章の例ではその状況を含んでいません。

結果リレーション

問い合わせの結果が格納されるリレーションを識別する範囲テーブルへのインデックスです。

SELECT問い合わせは結果リレーションを持ちません。 (SELECT INTOの場合は特別ですが、INSERT ... SELECTが付いたCREATE TABLEとほぼ同じですので、ここでは個別には説明しません。)

INSERTUPDATEDELETEコマンドでは、結果リレーションは変更が有効になるテーブル(もしくはビュー)です。

目的リスト

目的リストは問い合わせの結果を定義する式のリストです。 SELECTの場合、この式は問い合わせの最終結果を構築するものです。 これらはSELECTFROMキーワードの間にある式に対応します (*は単にリレーションの全ての列名の省略です。 これはパーサによって個別の列に展開されますので、ルールシステムが見ることはありません)。

DELETEコマンドは結果を返しませんので、通常の目的リストは必要ありません。 その代わり、プランナは空の目的リストに特別なCTID項目を追加し、エクゼキュータが削除すべき行を見つけられるようにします。 (CTIDは結果リレーションが通常のテーブルの場合に追加されます。 もしビューであれば40.2.4で述べるように、代わりに行全体の変数がルールシステムによって追加されます。)

INSERT問い合わせでは、目的リストは結果リレーションへ入る新規の行を示します。 これはVALUES句かINSERT ... SELECTの中のSELECT句の式です。 書き換え処理の最初のステップでは、元の問い合わせでは割り当てられず、デフォルト値となっている列の目的リストの項目を追加します。 残った列(値が与えられていない列、かつデフォルト値を持たない列)は全て、プランナによって定数NULL式で埋められます。

UPDATEコマンドでは、目的リストは古いものを置き換えるべき新しい行を示します。 ルールシステムではコマンド内のSET column = expression部分にある式だけを持っています。 プランナは、古い行から新しい行へ値をコピーする式を挿入することにより、抜けている列を処理します。 DELETEの場合と同様、エクゼキュータが更新すべき行を見つけられるように、CTIDもしくは行全体の変数が追加されます。

目的リストの各項目は、定数値、範囲テーブル内のリレーション中の1つの列を指し示す変数、パラメータ等の式を保持するか、または、関数呼び出し、定数、変数、演算子などにより作られた式のツリーを保持します。

条件

問い合わせの条件は目的リストの項目に含まれている式によく似た式です。 この式の結果は、最終的な結果の行を得るための(INSERTUPDATEDELETEまたはSELECT)演算を実行すべきかどうかを示すブール値です。 それはSQL文の中のWHERE句に対応します。

結合ツリー

問い合わせの結合ツリーはFROM句の構造を表します。 SELECT ... FROM a, b, cのような単純な問い合わせでは、結合ツリーは単なるFROM項目のリストです。 なぜならこれらはどんな順番で結合しても構わないためです。 しかしJOIN式、特に外部結合が使われた場合は、その結合が示す順番通りに結合しなければいけません。 この場合結合ツリーはJOIN式の構造を表します。 特定のJOIN句と関連付けられた制約(ONもしくはUSING式からのもの)はこれらの結合ツリーノードに付加された条件として格納されます。 頂点レベルのWHERE式を頂点レベルの結合ツリー項目に付加された条件として格納することも便利です。 ですから、結合ツリーはSELECTFROM句とWHERE句の両方を表しているわけです。

その他

ORDER BY句のような、問い合わせツリーのその他の部品は、ここでは取り上げません。 ルールシステムはルールを適用している時にそこで項目を入れ替えることもありますが、これはルールシステムの基本とはあまり関係しません。