0

私はpostgres9.1を使用していますが、後で更新したり、新しい行をビューに挿入したりできるビューを作成する方法について、いくつかのチュートリアルを見つけるのに苦労しています。

誰かが更新可能で新しい行の挿入を受け入れることができるビューを実行する方法についてのガイダンスを教えてもらえますか?

4

2 に答える 2

2

更新可能なビューはやや複雑です。それらを行うには 2 つの方法があります。1 つは RULE を使用し、もう 1 つは TRIGGER を使用します。トリガーはより多くのパフォーマンスの問題を引き起こしますが、RULE はより微妙なコーディングの問題を引き起こします。ここでは両方のアプローチについて説明します。

ベース テーブルと、ベース テーブルの一部へのアクセスを提供するビューがあるとします。

CREATE TABLE mybase (
      id serial primary key,
      type_id int not null,
      payload text not null
 );

 CREATE VIEW type1 AS select * from mybase WHERE type_id = 1;

わかりました、十分に簡単です。次に、ビューを更新可能にします。古い方法 (メンテナンスの落とし穴) は、ルールを使用することです。

 CREATE RULE on_insert AS ON insert TO type1 
 DO INSTEAD INSERT into mybase(id, type_id, payload) VALUES (new.id, 1, payload);

 CREATE RULE on_update AS ON update TO type1
 DO INSTEAD UPDATE mybase set payload = new.payload where id = old.id;

これで動作しますが、いくつか注意点があります。1つ目は、次の場合です。

 INSERT INTO type1 (id, type_id, payload) values (DEFAULT, 2, 'foo');

代わりに、2 ではなく 1 を静かに入力します。これは望ましくない場合があります。コードをより複雑にするか、関数を呼び出して挿入と更新を行うことができますが、RULE には計画時にクエリに解析されるという利点があり、関数は行ごとに 1 回実行されるため、100 万回更新する更新行は、関数よりも単純なルールの方がはるかに優れたパフォーマンスを発揮します。ルールを正しく設定するのは複雑で注意が必要ですが、それは、ビューへの更新が、ベース テーブルへの更新への書き込みと同じようにスケールアップすることを意味します。

ただし、複数のテーブルがある場合、複数の行を更新または削除し、これが (行ごとではなく) 計画時にマージされるため、事態ははるかに複雑になります。削除する必要があるものを見つけます。しかし、関数を使用すると、削除と更新で書き込みスケーリングの問題が発生します (これにより、基本的にインデックス スキャン ループが繰り返されます)。

もう 1 つのオプションは、トリガーを使用することです。トリガーは、書き込まれる行ごとに呼び出される関数であるため、関数を呼び出すルールの書き込みスケーリングの問題があります。このアプローチでは、トリガー関数を作成し、ビューにトリガーを作成します。

CREATE OR REPLACE FUNCTION type1_trigger_func() RETURNS trigger LANGUAGE PLPGSQL AS 
$$
BEGIN
  IF TG_OP = 'INSERT' THEN
     IF new.type_id <> 1 THEN RAISE EXCEPTION 'Invalid type!'; END IF;
     insert into mybasetable (id, type_id, payload) 
     VALUES (new.id, new.type_id, new.payload);
     RETURN NEW;
  ELSIF TG_OP = 'UPDATE' THEN
     IF new.type_id <> 1 THEN RAISE EXCEPTION 'Invalid type!'; END IF;
     -- update statement goes here
     RETURN NEW;
  ELSIF TG_IP = 'DELETE' THEN
     DELETE FROM mybasetable WHERE id = old.id;
     RETURN OLD;
  END IF;
END;
$$;

次に、トリガーを作成します。

 CREATE TRIGGER make_updateable INSTEAD OF INSERT OR UPDATE OR DELETE ON TYPE1
 FOR EACH ROW EXECUTE PROCEDURE type1_trigger_func();

一般に、このコンテキストでの RULE と TRIGGER の難しさから、私はビューではなくストアド プロシージャに傾倒しました。

于 2013-03-10T15:31:54.617 に答える