我们在PostgresQL中最接近“在COMMIT上刷新完成”是什么?

问题描述 投票:0回答:1

因此,我们正在寻找一种方法来实施跨越多个表的约束。

我们遇到了this old blog post,这表明:

  • 创建实例化视图以选择违反所需约束的数据。 MV必须用REFRESH COMPLETE ON COMMIT定义,以便在事务结束之前进行更新。

  • 在物化视图上创建检查约束,该约束总是评估为FALSE –例如CHECK (1=0)

就是这样。每当更新基础表时,都会刷新实例化视图。如果更新违反了规则,那么将在实例化视图中插入一行;但是对MV的检查约束不允许对其进行任何插入,因此事务失败。

尽管有一些性能问号,但这个想法听起来很合理。

但是,据我们所知,postgresql不支持REFRESH ON COMMIT之类的东西。

当然,我们可以做的是在构成视图的表上安装触发器,这些触发器将触发对更新/删除/插入的刷新。

但是不仅可能意味着必须对每个涉及的表执行刷新,而且在执行刷新时,我们可能还早已结束了事务。

也许我们可以用锁定来做一些事情,但是这很快就变成了锁定正确的事情的问题,这听起来像一个可怕的主意。

所以我们有什么可以做的,还是我们最好忘掉这个?

我们最接近“提交前刷新”行为的是什么?

postgresql locking constraints database-trigger
1个回答
0
投票

不要创建实例化视图,请手动滚动。

作为示例,我们有两个表ab,并且我们要确保这两个表中的行之和小于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;
© www.soinside.com 2019 - 2024. All rights reserved.