この...
- ...それは
- (うまくスケール)ルートでのトリガーの複数の呼び出しを避けるためにも、うまくを実行する必要があります...は、(追加の行は変更されません。テーブルの膨らみを最小限に抑えます)
- ...高価な例外処理は必要ありません。
は、テスト環境として別のスキーマx
ではPostgreSQL 9.1でテストされ、次の
デモ
を考えてみましょう。
テーブルとダミー行
-- DROP SCHEMA x;
CREATE SCHEMA x;
CREATE TABLE x.tbl (
id int
,counter int
,trig_exec_count integer -- for monitoring payload execution.
,updated bool);
を挿入し、それが複数の行で動作実証する二列:
INSERT INTO x.tbl VALUES
(1, 0, 0, NULL)
,(2, 0, 0, NULL);
トリガ関数とトリガ
1)を実行し、高価なペイロード
CREATE OR REPLACE FUNCTION x.trg_upaft_counter_change_1()
RETURNS trigger AS
$BODY$
BEGIN
-- PERFORM some_expensive_procedure(NEW.id);
-- Update trig_exec_count to count execution of expensive payload.
-- Could be in another table, for simplicity, I use the same:
UPDATE x.tbl t
SET trig_exec_count = trig_exec_count + 1
WHERE t.id = NEW.id;
RETURN NULL; -- RETURN value of AFTER trigger is ignored anyway
END;
$BODY$ LANGUAGE plpgsql;
2.)行を更新済みとしてフラグを立てます。
CREATE OR REPLACE FUNCTION x.trg_upaft_counter_change_2()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE x.tbl
SET updated = TRUE
WHERE id = NEW.id;
RETURN NULL;
END;
$BODY$ LANGUAGE plpgsql;
3.) "updated"フラグをリセットします。
CREATE OR REPLACE FUNCTION x.trg_upaft_counter_change_3()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE x.tbl
SET updated = NULL
WHERE id = NEW.id;
RETURN NULL;
END;
$BODY$ LANGUAGE plpgsql;
トリガー名が該当します。アルファベット順に実行される同じイベントのために呼び出されます。
1)ペイロード、まだ "更新" ではない場合にのみ:まだ "更新" ではない場合にのみ、更新されたとして
CREATE CONSTRAINT TRIGGER upaft_counter_change_1
AFTER UPDATE OF counter ON x.tbl
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
WHEN (NEW.updated IS NULL)
EXECUTE PROCEDURE x.trg_upaft_counter_change_1();
2)フラグ行:
CREATE TRIGGER upaft_counter_change_2 -- not deferred!
AFTER UPDATE OF counter ON x.tbl
FOR EACH ROW
WHEN (NEW.updated IS NULL)
EXECUTE PROCEDURE x.trg_upaft_counter_change_2();
3)リセットフラグ。トリガ条件のため無限ループはありません。別途
CREATE CONSTRAINT TRIGGER upaft_counter_change_3
AFTER UPDATE OF updated ON x.tbl
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
WHEN (NEW.updated) --
EXECUTE PROCEDURE x.trg_upaft_counter_change_3();
テスト
実行UPDATE
& SELECT
繰延効果を確認します。 (1つのトランザクションで)一緒に実行されると、SELECTには新しいtbl.counter
が表示されますが、古いtbl2.trig_exec_count
が表示されます。
UPDATE x.tbl SET counter = counter + 1;
SELECT * FROM x.tbl;
ここで、(1つのトランザクションで)カウンタを複数回更新します。ペイロードは一度だけ実行されます。 Voilá!
UPDATE x.tbl SET counter = counter + 1;
UPDATE x.tbl SET counter = counter + 1;
UPDATE x.tbl SET counter = counter + 1;
UPDATE x.tbl SET counter = counter + 1;
UPDATE x.tbl SET counter = counter + 1;
SELECT * FROM x.tbl;
ご使用のバージョンのPostgresが役立ちます。トリガーとトリガー機能の(基本)コード。 –