ルール対トリガ

トリガによって行われる多くの操作は Postgres のルールシステムで実装 可能です。現在実際にルールで実装できないものはある種の制限 事項に関してです。 もし他のテーブルにカラム値がなかった場合、条件ルール で問合せを NOTHING に書き換えてしまうことも可能ですが、 これではデータがだまって消去されてしまい、よいアイデアとは いえません。有効な値が必要であるかどうかを判断し、無効な値 の時はエラーを返すべきです。このことは今のところトリガを使 って行なわなければなりません。

一方、ビュー上で INSERT によって駆動されたトリガは、 データをどこかに退避させ、ビューへの挿入を禁止するルール と同じことができます。しかし UPDATE または DELETE では スキャンされる実データがビューリレーションに存在しないので トリガが呼ばれることがない点で相違しています。ルールでの 解決しかありません。

いずれによっても実装されるこれらの機能に関してどちらが ベストかはデータベースの使用法によります。 トリガはどの行にたいしても一度だけ起動します。ルールは パースツリーを操作するか追加のパースツリーを生成します。 ですから、一つの命令文が多くの行に影響を与える場合、一つ の行を処理するたびに呼び出し操作の実行を何回も行わなければなら ないトリガよりも、一つの別の問合せを発行するルールのほうが 通常よい働きをします。

例えば、二つのテーブルがあるとします。

    CREATE TABLE computer (
        hostname        text     -- インデックス付き
	manufacturer    text     -- インデックス付き
    );

    CREATE TABLE software (
        software        text,    -- インデックス付き
        hostname        text     -- インデックス付き
    );
<!- Both tables have many thousands of rows and the index on hostname is unique. The hostname column contains the full qualified domain name of the computer. The rule/trigger should constraint delete rows from software that reference the deleted host. Since the trigger is called for each individual row deleted from computer, it can use the statement --> 二つのテーブルには共に数千の行があって、hostname 上の 索引は一意です。hostname のカラムにはコンピュータの FQDN (絶対ドメイン名)があります。 ルール/トリガは削除されたホストを参照する software による行削除を制限しなければなりません。 トリガは computer から削除されたそれぞれの独立した 行で呼び出されますので、
    DELETE FROM software WHERE hostname = $1;
という命令文を、準備され保存されたプランの中で使用し パラメータ中に hostname を引き渡すことができます。 この時のルールは以下のように書き表すことができます。
    CREATE RULE computer_del AS ON DELETE TO computer
        DO DELETE FROM software WHERE hostname = OLD.hostname;
ここで、異なった種類の削除について見てみましょう。
    DELETE FROM computer WHERE hostname = 'mypc.local.net';
この場合、テーブル computer はインデックスでスキャン され(高速です)、トリガによって発行された問合せも同様 インデックススキャンとなります(これも高速です)。 ルールからの特別の問合せは以下のようになります。
    DELETE FROM software WHERE computer.hostname = 'mypc.local.net'
                           AND software.hostname = computer.hostname;
そこには適切なインデックスが用意されているので、オプティマイザ は以下のプランを生成します。
    ネストしたループ
      ->  computer 上で comp_hostidx を使ったインデックススキャン 
      ->  software 上で soft_hostidx を使ったインデックススキャン
トリガとルール実装の間で処理速度の差はそれほどは無いでしょう。 次の削除処理では hostname が 'old' で始まる 2000 全ての computer を削除しようと思います。方法として二つの有効な 問合せがあって、一つは
    DELETE FROM computer WHERE hostname >= 'old'
                           AND hostname <  'ole'
ここで問合せのルールに対するプランは
    ハッシュ ジョイン
      ->  software 上で逐次スキャン
      ->  ハッシュ
	    ->  computer 上で comp_hostidx をつかったインデックススキャン
もう一つの問合せは
    DELETE FROM computer WHERE hostname ~ '^old';
で、以下の実行プランを持っています。
    ネストしたループ
      ->  computer 上で comp_hostidx を使ったインデックススキャン
      ->  software 上で soft_hostidx を使ったインデックススキャン
これが示していることは、オプティマイザは、regexp バージョンでは 行った、AND で結合された複数の制約式が存在する場合 computer 上 の hostname に対する制約が、software 上のインデックススキャン にも同様に使用出来ることを、実現出来ません。 トリガは削除されるべき 2000 台の旧式コンピュータのいずれかによ って一回呼び出され、結果 computer 上で一回のインデックススキャン と software に対して 2000 のインデックススキャンが行われます。 ルールの実装でインデックス上で二つの問合せによって実行されます。 逐次スキャンにおいてルールがより速い場合、総体的な software テーブルの大きさに依存します。 参照する全てのインデックスブロックが間もなくキャッシュに現れる としても、 SPI マネージャに対する 2000 の問合せの実行には時間を 要します。

最後の問合せを見てみましょう。

    DELETE FROM computer WHERE manufacurer = 'bim';
もう一度、この文で computer から削除される沢山の行が検出される 結果となります。トリガはそこで再度数多くの問合せをエクゼキュータ に駆動をかけます。とは言っても、ルールプランは二つのインデックス スキャンのネストループとなります。computer に対して他の インデックスを単に使えば
    ネストループ
      ->  computer に対して comp_manufidx を使用したインデックススキャン
      ->  software に対して soft_hostidx を使用したインデックススキャン

    これらのルール問合せの結果は、
    DELETE FROM software WHERE computer.manufacurer = 'bim'
                           AND software.hostname = computer.hostname;
いずれの場合においても、ルールシステムからの特別な問合せ は問合せの中で影響を受ける行数とはおおむね独立しています。

別の状況として、アクションを実行すべきか否かが変更された属性に依存する、 UPDATEの場合があります。Postgres 6.4では、ルールイベントにおける属性指定 はできなくなっています。(遅くとも 6.5 あるいはもう少し早くに使えるように なるでしょう。チューニング中です。) したがって、現時点で shoelace_log の 例のようにルールを作成する唯一の方法はルール条件を使用することです。初め の問合せの目的リストに出て来ないため、これは対象とする属性が変更されなく ても常に実行される特別な問合せとなります。 再度使えるようになった場合はトリガに対するルールの更に一つの強みになります。 この場合、トリガの最適化はその定義により不可能です。特定の属性が変更された 時にのみそのアクションを行なうという処理自体はその(トリガ)関数内部に隠さ れているからです。トリガの定義は行レベルのみに対して認められるので、行が触 られるとトリガは呼び出され、アクションを行なうかどうかを決定しなければなり ません。ルールシステムの場合は対象リストを検索することで変更されたかどうか 判りますので、属性が触られていなければその後の問合せをすべて中止することが できます。条件の有無に関わらず、ルールは実行しなければならないことがあれば スキャンを実行します。

ルールはトリガよりもそのアクション結果が大きい場合、間違った 条件づきのジョイン、オプティマイザが失敗した場合のみ著しく遅く なります。大きな金槌の様なもので、注意を怠ると大怪我をしますが うまく使えばどんな釘でも正確に頭を叩けます。