Что ближе всего мы можем получить к `REFRE SH COMPLETE ON COMMIT` в PostgresQL? - PullRequest
0 голосов
/ 28 января 2020

Итак, мы ищем способ применения ограничений, охватывающих несколько таблиц.

Мы натолкнулись на эту старую запись в блоге , которая предлагает:

  • Создать материализованное представление для выбора данных, которые нарушают желаемое ограничение. MV должен быть определен с помощью REFRESH COMPLETE ON COMMIT, чтобы он обновлялся до конца транзакции.

  • Создайте проверочное ограничение для материализованного представления, которое всегда оценивается как FALSE - например, CHECK (1=0)

Вот и все. Всякий раз, когда базовые таблицы обновляются, материализованное представление обновляется. Если обновление нарушает правило, то строка будет вставлена ​​в материализованное представление; но проверочное ограничение на MV запрещает любые вставки в него, и поэтому транзакция завершается неудачей.

И хотя существуют некоторые вопросительные знаки производительности, идея звучит достаточно разумно.

Однако, postgresql - насколько нам известно - не поддерживает что-то вроде REFRESH ON COMMIT.

Что мы можем, конечно, сделать, это установить триггеры на таблицы, которые формируют представление, которое вызовет refre sh при обновлении / удалении / вставке.

Но это может не только означать необходимость выполнения refre sh для каждой из задействованных таблиц, мы также могли долго завершать транзакцию к тому времени, когда refre sh выполняется.

Возможно, мы могли бы что-то сделать с блокировкой, но тогда возникает проблема с блокировкой правильной вещи достаточно быстро, что звучит как ужасная идея.

Так что-то есть? мы можем сделать, или нам лучше забыть об этом?

Что ближе всего к поведению "refre sh before commit"?

1 Ответ

0 голосов
/ 29 января 2020

Не создавайте материализованное представление, сверните его вручную.

Например, у нас есть две таблицы a и b, и мы хотим убедиться, что сумма строк в этих двух таблицах меньше 1000:

BEGIN;

CREATE TABLE counter (
   total bigint NOT NULL,
   CHECK (total < 1000)
);

CREATE FUNCTION count_trig() RETURNS trigger
   LANGUAGE plpgsql AS
$$BEGIN
   CASE
      WHEN TG_OP = 'INSERT' THEN
         UPDATE counter SET total = total + 1;
         RETURN NEW;
      WHEN TG_OP = 'DELETE' THEN
         UPDATE counter SET total = total - 1;
         RETURN OLD;
   END CASE;
END;$$;

CREATE TRIGGER count_trig AFTER INSERT OR DELETE ON a
   FOR EACH ROW EXECUTE PROCEDURE count_trig();

CREATE TRIGGER count_trig AFTER INSERT OR DELETE ON b
   FOR EACH ROW EXECUTE PROCEDURE count_trig();

INSERT INTO counter (total)
   VALUES ((SELECT count(*) FROM a) + (SELECT count(*) FROM b));

COMMIT;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...