Chapter 17. Postgres のルールシステム

Table of Contents
17.1. 問い合わせツリーとは何か?
17.2. ビューとルールシステム
17.3. INSERT、 UPDATE および DELETE についてのルール
17.4. ルールと権限
17.5. ルール対トリガ

著者: Jan Wieck によって書かれました。7.1 用に Tom Laneが更新しました。

本番で稼働するルールシステムは概念としては単純ですが、実際に使って みると、判りにくいところが少なからずあります。これらいくつかの判りにくい ところと、Postgresのルールシステム における基本的な理論については[Stonebraker et al, ACM, 1990] に書かれています。

他のいくつかのデータベースシステムは能動的データベースルールを 定義しています。通常それらは格納されたプロシージャとトリガで、 Postgresでは関数とトリガとして 実装されています。

問い合わせリライトシステム(以降"ルールシステム"と呼びます)は内蔵 プロシージャとトリガとは全く異なります。ルールシステムはルールを 参照して問い合わせを修正し、修正した問い合わせを、プラン作成と 実行のためにクエリープランナに渡します。これは非常に強力なため、問い合わせ言語プロシージャ、 ビューあるいはバージョンなど多くのパターンでしようすることが できます。このルールシステムの能力は[Ong and Goh, 1990] や[Stonebraker et al, ACM, 1990]で解説されています。

17.1. 問い合わせツリーとは何か?

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

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

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

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

17.1.1. 問い合わせツリーのパーツ

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

コマンド型

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

範囲テーブル

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

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

結果リレーション

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

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

INSERT, UPDATE そして DELETE 問い合わせでは、結果は変化が 有効になるテーブル(もしくはビュー!)です。

目的リスト

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

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

INSERT では目的リストは結果のリレーションへ行く新規の 行を記述します。それは VALUES 句か INSERT ... SELECT のなかの SELECT 句の式です。結果のリレーションで抜けているカラムは プランナが定数 NULL 式によって埋めます。

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

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

条件

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

結合ツリー

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

その他

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