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

Изпълнявайте отложен тригер само веднъж на ред в PostgreSQL

Това е труден проблем. Но може да се направи с тригери за всяка колона и условно изпълнение на тригери, въведени в PostgreSQL 9.0 .

Нуждаете се от „актуализиран“ флаг на ред за това решение. Използвайте boolean колона в същата таблица за простота. Но може да е в друга таблица или дори във временна таблица на транзакция.

Скъпият полезен товар се изпълнява веднъж на ред където броячът се актуализира (веднъж или многократно).

Това също трябва да работи добре, защото ...

  • ... той избягва множество извиквания на тригери в основата (добре мащабира)
  • ... не променя допълнителните редове (минимизиране на раздуването на таблицата)
  • ... не се нуждае от скъпа обработка на изключения.

Помислете за следното

Демо

Тествано в PostgreSQL 9.1 с отделна схема x като тестова среда.

Таблици и фиктивни редове

-- 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.) Нулирайте флага „актуализиран“.

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 отделно, за да видите отложения ефект. Ако се изпълни заедно (в една транзакция), SELECT ще покаже новия tbl.counter но старият tbl2.trig_exec_count .

UPDATE x.tbl SET counter = counter + 1;

SELECT * FROM x.tbl;

Сега актуализирайте брояча няколко пъти (в една транзакция). Полезният товар ще бъде изпълнен само веднъж. Вуаля!

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. 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. Изберете тип данни на полето в postgres

  3. Анотация за хибернация за сериен тип PostgreSQL

  4. Postgres ръчно променя последователността

  5. След възстановяване на моята база данни серийният номер е премахнат от колоната в Postgresql