要約値を維持するのは難しいです。
本当にこれを行う必要がある場合は、パフォーマンスの問題が発生することがわかっているため(数百以上の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;