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

挿入後にテーブルの値をインクリメントするトリガーを作成する必要があります

    要約値を維持するのは難しいです。デッドロック の可能性を簡単に作成できます。 あなたのプログラム。

    本当にこれを行う必要がある場合は、パフォーマンスの問題が発生することがわかっているため(数百以上のnhuntなど)、nhunt用に次のような個別の要約テーブルを作成することをお勧めします。

    CREATE TABLE hunts_summary
    (
        id_hs bigserial primary key,
        id_h integer NOT NULL,
        nhunts integer NOT NULL
    );
    CREATE INDEX hunts_summary_id_h_idx on hunts_summary(id_h);
    

    狩りの引き金:

    • 追加、削除、更新された行ごとに実行されます。
    • 行を追加します(id_h, nhunts) = (NEW.id_h, 1) 各インサートに;
    • 行を追加します(id_h, nhunts) = (OLD.id_h, -1) 削除するたびに;
    • id_hを変更する更新に関する上記の両方 。

    トリガーは新しい行を追加するだけなので、既存の行をロックせず、デッドロックすることはできません。

    ただし、これだけでは不十分です。前述のように、サマリーテーブルは、ハントテーブルと同じかそれよりも速く行を拡張するため、あまり役に立ちません。したがって、既存の行を定期的にマージする方法を追加する必要があります。変更する方法は次のとおりです。

    id_h nhunts
    1    1
    1    1
    2    1
    2    -1
    1    1
    1    -1
    2    1
    1    1
    2    1
    

    宛先:

    id_h nhunts
    1    3
    2    2
    

    これは、トリガーの呼び出しごとに実行するべきではありません。非常に遅くなるためですが、ランダムに実行できます。たとえば、1/1024回の呼び出しごとにランダムに実行できます。この関数は「skiplocked」キーワードを使用して、すでにロックされている行に触れないようにし、そうでなければデッドロックが発生する可能性を回避します。

    このようなトリガーは次のようになります。

    create or replace function hunts_maintain() returns trigger
    as $hunts_maintain$
            begin
                    if (tg_op = 'INSERT') then
                            insert into hunts_summary(id_h, nhunts)
                                    values (NEW.id_h, 1);
                    elsif (tg_op = 'DELETE') then
                            insert into hunts_summary(id_h, nhunts)
                                    values (OLD.id_h, -1);
                    elsif (tg_op = 'UPDATE' and NEW.id_h!=OLD.id_h) then
                            insert into hunts_summary(id_h, nhunts)
                                    values (OLD.id_h, -1), (NEW.id_h, 1);
                    end if;
    
                    if (random()*1024 < 1) then
                            with deleted_ids as (
                                    select id_hs from hunts_summary for update skip locked
                            ),
                            deleted_nhunts as (
                                    delete from hunts_summary where id_hs in (select id_hs from deleted_ids) returning id_h, nhunts
                            )
                            insert into hunts_summary (id_h, nhunts) select id_h, sum(nhunts) from deleted_nhunts group by id_h;
                    end if;
    
                    return NEW;
            end;
    $hunts_maintain$ language plpgsql;
    
    create trigger hunts_maintain
            after insert or update or delete on hunts
            for each row execute procedure hunts_maintain();
    

    トリガーは私のラップトップで十分に速く実行され、45秒でテーブルをハントするために100万行を挿入します。

    以下のこのビューにより、要約から現在のnhuntを簡単に抽出できます。ハントテーブルが数十億になる場合でも、クエリを実行するには数またはミリ秒かかります。

    create or replace view hunts_summary_view as
            select id_h, sum(nhunts) as nhunts
            from hunts_summary
            group by id_h;
    



    1. OracleSQL-レコードの日付と履歴に基づいてレコードにフラグを立てます

    2. MySQLのフィールドから最初の明確な一致のみを選択するにはどうすればよいですか?

    3. 日付範囲の日付を確認する方法は、mysqlクエリの2つの日付の間にあります

    4. 列の合計または新しい列