sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLの行ごとに1回だけ遅延トリガーを実行します

    これは難しい問題です。ただし、 PostgreSQL 9.0で導入された列ごとのトリガーと条件付きトリガーの実行を使用して実行できます。 。

    行ごとに「更新された」フラグが必要です このソリューションのために。 booleanを使用する 簡単にするために、同じテーブルの列。ただし、別のテーブルにある場合もあれば、トランザクションごとの一時テーブルにある場合もあります。

    高価なペイロードは行ごとに1回実行されます カウンターが更新される場所(1回または複数回)。

    これも実行する必要があります まあ、なぜなら...

    • ...ルートでのトリガーの複数の呼び出しを回避します(適切にスケーリングします)
    • ...追加の行を変更しません(テーブルの肥大化を最小限に抑えます)
    • ...高価な例外処理は必要ありません。

    次のことを考慮してください

    デモ

    別のスキーマxを使用してPostgreSQL9.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);
    

    2つの行を挿入して、複数の行で機能することを示します。

    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。)「更新済み」フラグをリセットします。

    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つのトランザクションで)。ペイロードは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;
    


    1. JSON_SET()–MySQLのJSONドキュメントに値を挿入または更新します

    2. テーブルから上位N行を選択します

    3. SqlCommandを使用して、パラメーター化されたデータベース名でデータベースを作成するにはどうすればよいですか?

    4. MSSQLServerでのデータベーススキーマ変更の自動データ収集