ルール対トリガ

PostgreSQL 9.1.1文書
前のページ | 巻戻し | 第 37章ルールシステム | 早送り | 次のページ

# 37.6. ルール対トリガ

トリガによって行われる多くの操作はPostgreSQLのルールシステムで実装可能です。 ルールで実装できないものの1つはある種の制約、特に外部キーに関してです。 もし他のテーブルに列の値がなかった場合、条件ルールでコマンドを`NOTHING`に書き換えてしまうことも可能ですが、これではデータがだまって消去されてしまい、良いアイディアとは言えません。 有効な値かどうかのチェックが必要で、無効な値についてはエラーメッセージを表示する必要があるなら、このことは今のところトリガを使って行わなければなりません。

この章ではビューを更新するのにルールを使うことに焦点を当ててきました。 この章の更新ルールの例はすべてビューの`INSTEAD OF`トリガを使っても実装できます。 特に更新を実行するのに複雑な論理が要求される場合には、そのようなトリガを書くことはしばしばルールを書くよりも簡単です。

どちらでも実装できる事項に関してどちらがベストかはデータベースの使用法によります。 トリガは各行に対して一度起動します。 ルールは問い合わせを修正するか追加の問い合わせを生成します。 ですから、1つの文が多くの行に影響を与える場合、1つの行を処理する度に呼び出され、何をするかを何度も再決定しなければならないトリガよりも、追加の問い合わせを1つ発行するルールの方がほとんどの場合高速になります。 しかし、トリガ方式は概念的にルールシステムよりかなり単純であり、初心者は簡単に正しく扱うことができます。

ここで、ある状況下でルールとトリガのどちらを選択するかを示す例を挙げます。 例えば、2つのテーブルがあるとします。

    CREATE TABLE computer (
        hostname        text,    -- インデックスあり
        manufacturer    text     -- インデックスあり
    );

    CREATE TABLE software (
        software        text,    -- インデックスあり
        hostname        text     -- インデックスあり
    );

2つのテーブルにはともに数千の行があって、`hostname`上のインデックスは一意です。 ルール/トリガは削除されたホストを参照する、`software`の行を削除する制限を実装しなければなりません。 トリガの場合は以下のコマンドを使用します。

    DELETE FROM software WHERE hostname = $1;

`computer`から削除された行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`で始まる2,000台全てのcomputerを削除しようと思います。 方法として2つの有効な問い合わせがあって、1つは以下のようなものです。

    DELETE FROM computer WHERE hostname >= 'old'
                           AND hostname <  'ole'

ルールによって追加されるコマンドは以下のようになります。

    DELETE FROM software WHERE computer.hostname >= 'old' AND computer.hostname < 'ole'
                           AND software.hostname = computer.hostname;

これに対する計画は以下のようになります。

    ハッシュ結合
      ->  softwareに対するシーケンシャルスキャン
      ->  ハッシュ
        ->  computerに対するcomp_hostidxを使用するインデックススキャン

もう1つのコマンドは以下のようなものです。

    DELETE FROM computer WHERE hostname ~ '^old';

これにより、ルールによって追加されるコマンド用の実行計画は以下のようになります。

    入れ子状ループ
      ->  computerに対するcomp_hostidxを使用するインデックススキャン
      ->  softwareに対するsoft_hostidxを使用するインデックススキャン

これが示していることは、`AND`で結合された複数の検索条件が存在する場合、プランナは正規表現版のコマンドでは行っていることですが、`computer`上の`hostname`に対する検索条件を`software`上のインデックススキャンにも同様に使用できることを理解しないということです。 トリガは削除されるべき2,000台の旧式コンピュータのそれぞれについて1回呼び出され、結果`computer`上で1回のインデックススキャンと`software`上で2,000回のインデックススキャンが行われます。 ルールによる実装ではインデックスを使用する2つの問い合わせによって実行されます。 シーケンシャルスキャンの場合でもルールがより速いかどうかは`software`テーブルの大きさに依存します。 参照する全てのインデックスブロックがすぐにキャッシュに現れるとしても、トリガによるSPIマネージャ経由の2,000回のコマンドの実行には時間を要します。

最後のコマンドを見てみましょう。

    DELETE FROM computer WHERE manufacturer = 'bim';

この文でも`computer`から多くの行が削除される結果となります。 ですので、ここでもトリガはエクゼキュータを通して多くのコマンドを実行することになります。 ルールで作成されるコマンドは以下のようなものです。

    DELETE FROM software WHERE computer.manufacturer = 'bim'
                           AND software.hostname = computer.hostname;

このコマンド用の計画もまた前回同様2つのインデックススキャンの入れ子状ループとなります。 `computer`の別のインデックスを使用する点のみが異なります。

    入れ子状ループ
      ->  computerに対するcomp_manufidxを使用するインデックススキャン
      ->  softwareに対するsoft_hostidxを使用するインデックススキャン

いずれの場合においても、ルールシステムが生成する追加コマンドは影響を受ける行数からは多かれ少なかれ独立しています。

まとめると、問い合わせ結果が大きく、プランナがうまく結合条件を設定できないような状況下でのみルールはトリガに比べて明らかに遅くなります。

前のページ | ホーム | 次のページ
ルールおよびコマンドの状態 | 上に戻る | 手続き言語