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

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

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

では問い合わせツリーとは何でしょうか。それは、SQL 文を構成する個々の部品を別々に記憶した、SQL 文の内部表現です。PostgreSQLバックエンドをデバッグレベル4で起動し、対話型バックエンドインターフェイスを使って問い合わせを入力することによって、問い合わせツリーを見ることができます。pg_rewriteシステムカタログ内のルールアクションは同時に、問い合わせツリーとして記憶されます。それらはデバッグ出力のようにフォーマットされてはいませんが、まったく同じ情報を持っています。

問い合わせツリーを読むためにはある程度の経験が必要になり、著者自身、ルールシステムを始めた頃は大変でした。今でも覚えていますが、コーヒーマシンの前に立っていたとき、コップが目的リストに、水とコーヒーの粉は範囲テーブルに、そしてすべてのボタンは制約式に見えたものです。SQLの問い合わせツリー表現形式はルールシステムを理解するためには十分なので、ここではその読み方までは教えません。自分で勉強しておけば役に立つでしょうし、名前付けの慣習は後に出てくる説明で必要になります。

13.2.1. 問い合わせツリーの部品

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

コマンドタイプ。

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

範囲テーブル

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

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

結果リレーション

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

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

INSERT、UPDATE、DELETE問い合わせでは、結果リレーションは変化が有効になるテーブル(もしくはビュー)です。

目的リスト

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

DELETE問い合わせは結果を返さないので目的リストが必要ありません。 実際には、プランナが空の目的リストに特別な CTID 項目を追加します。しかしこれは、後に説明しますが、ルールシステムの後に行われます。ルールシステムでは目的リストは空です。

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

UPDATE問い合わせでは、目的リストは古いものを置き換えるべき新しい行を示します。ルールシステムでは問い合わせの「SET 属性 = 式」の部分からの式だけを持っています。 プランナは、古い行から新しい行へ値をコピーする式を挿入することにより、抜けている列を処理します。 そして、DELETE の場合と同様に、特別な CTID 項目を追加します。

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

条件

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

結合ツリー

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

その他

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