我经常看到它说rules should be avoided and triggers used instead。我可以看到规则系统中的危险,但当然有规则的有效用途,对吧?它们是什么?
我出于一般兴趣而提出这个问题;我对数据库不太熟悉。
例如,过去我需要锁定某些数据,所以我做了类似的事情:
CREATE OR REPLACE RULE protect_data AS
ON UPDATE TO exampletable -- another similar rule for DELETE
WHERE OLD.type = 'protected'
DO INSTEAD NOTHING;
然后,如果我想编辑受保护的数据:
START TRANSACTION;
ALTER TABLE exampletable DISABLE RULE protect_data;
-- edit data as I like
ALTER TABLE exampletable ENABLE RULE protect_data;
COMMIT;
我同意这是hacky,但在这种情况下我无法更改访问数据库的应用程序(甚至在它上面抛出错误)。所以奖励积分用于查找对规则系统的危险/无效使用的原因,但不为什么这是糟糕的设计。
答案 0 :(得分:15)
RULES的一个用例是可更新的视图(尽管9.1中的更改因为该版本为视图引入了INSTEAD OF触发器)
另一个很好的解释可以在手册中找到:
对于两者都可以实现的事情,最好取决于数据库的用法。为任何受影响的行触发一次触发器。规则操纵查询或生成其他查询。因此,如果在一个语句中影响了许多行,则发出一个额外命令的规则可能比为每一行调用的触发器更快,并且必须多次执行其操作。但是,触发器方法在概念上远比规则方法简单,并且新手更容易正确。
(摘自:http://www.postgresql.org/docs/current/static/rules-triggers.html)
答案 1 :(得分:11)
这里显示了一些规则问题:http://www.depesz.com/index.php/2010/06/15/to-rule-or-not-to-rule-that-is-the-question/(例如,如果查询中包含random(),它可能会执行两次并返回不同的值)。
规则的最大缺点是人们不理解。
例如,有人可能会认为有这样的规则:
CREATE OR REPLACE RULE protect_data AS
ON UPDATE TO exampletable -- another similar rule for DELETE
WHERE OLD.type = 'protected'
DO INSTEAD NOTHING;
意味着如果我发出:
update exampletable set whatever = whatever + 1 where type = 'protected'
不会运行任何查询。哪个不是真的。查询将运行,但它将以修改后的版本运行 - 添加条件。
更重要的是 - 规则打破非常有用的东西,即返回子句:
$ update exampletable set whatever = whatever + 1 where type = 'normal' returning *;
ERROR: cannot perform UPDATE RETURNING on relation "exampletable"
HINT: You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.
要包装它 - 如果你真的,真的,肯定必须使用可写视图,并且你正在使用9.1之前的PostgreSQL - 你可能有正当理由使用规则。
在所有其他情况下 - 即使你没有立即看到它,你最有可能用脚射击自己。
答案 2 :(得分:8)
在处理易失性函数时,我对规则有一些痛苦的经历(如果内存服务,depesz'博客文章突出显示其中一些)。
由于fkey触发器被触发的时间,我在使用它时也破坏了引用完整性:
CREATE OR REPLACE RULE protected_example AS
ON DELETE TO example
WHERE OLD.protected
DO INSTEAD NOTHING;
...然后添加另一个表,并使用on delete cascade外键作为示例引用该表。然后,从那张桌子上删除* ......然后惊恐地退缩。
我将上述问题报告为一个错误,该错误被视为一个功能/必要的边缘情况。仅仅几个月后,我才明白为什么会这样,即fkey触发器完成它的工作,然后规则开始并自行完成,但fkey触发器不会检查其工作是否因性能原因而正确完成
我仍然使用规则的实际用例是当预先操作数据的BEFORE
触发器(SQL标准不允许,但Postgres很乐意)可以导致预先操纵受影响的数据行,从而更改它们的ctid(即它会更新两次,或者因为更新使删除无效而不会被删除)。
这导致Postgres返回不正确数量的受影响的行,这在您发出后续语句之前监视该数字之前没什么大不了的。
在这种情况下,我发现使用策略性放置的规则或两个规则可以允许先发制人地执行违规声明,从而导致Postgres返回正确数量的受影响行。
答案 3 :(得分:5)
这个怎么样:你有一个需要更改为视图的表。为了支持插入到表中的遗留应用程序,创建了一个规则,将“插入”映射到新视图到基础表。