PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Необходимо е да се създаде тригер, който увеличава стойност в таблица след вмъкване

Поддържането на обобщена стойност е трудно - лесно е да създадете възможност за deadlock вашата програма.

Ако наистина трябва да направите това, защото знаете, че в противен случай ще имате проблеми с производителността (като nhunts в стотици или повече), тогава е по-добре да създадете отделна обобщена таблица за nhunts, нещо като:

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-то извикване на случаен принцип. Тази функция ще използва ключова дума "skip locked", за да избегне докосването на вече заключени редове, избягвайки в противен случай възможна блокиране.

Такова задействане би изглеждало по следния начин:

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();

Тригерът работи достатъчно бързо на моя лаптоп, за да вмъкне 1 милион реда в таблицата за търсене за 45 секунди.

Този изглед по-долу ще улесни извличането на текущи nhunts от резюмето. Запитването ще отнеме малко число или ms, дори ако таблицата за търсене ще бъде в милиарди:

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Вмъкнете, ако не съществува, иначе върнете идентификатора в postgresql

  2. Актуализирайте няколко колони, които започват с конкретен низ

  3. Еволюция на отказоустойчивостта в PostgreSQL:Фаза на репликация

  4. Android OS и postgreSQL

  5. Изпращане на масив от стойности към sql заявка в ruby?