许多可以使用触发器完成的事情也可以使用PostgreSQL规则系统来实现。规则无法实现的事情之一是一些类型的约束,特别是外键。可以放置一个限定规则,如果列的值未出现在另一个表中,则将命令重写为NOTHING
。但随后数据会被静默丢弃,这不是一个好主意。如果需要检查有效值,并且在无效值的情况下应生成错误消息,则必须通过触发器来完成。
在本章中,我们重点介绍了使用规则更新视图。本章中的所有更新规则示例也可以使用视图上的INSTEAD OF
触发器来实现。编写此类触发器通常比编写规则更容易,尤其是在需要复杂的逻辑来执行更新时。
对于可以使用两者实现的事情,哪种方法更好取决于数据库的使用方式。触发器针对每个受影响的行触发一次。规则修改查询或生成额外的查询。因此,如果在一个语句中影响了许多行,则发出一个额外命令的规则可能比针对每一行都调用的触发器更快,并且触发器必须多次重新确定要执行的操作。但是,触发器方法在概念上比规则方法简单得多,并且初学者更容易掌握。
在这里,我们展示了一个规则与触发器选择在一种情况下如何发挥作用的示例。有两个表
CREATE TABLE computer ( hostname text, -- indexed manufacturer text -- indexed ); CREATE TABLE software ( software text, -- indexed hostname text -- indexed );
这两个表都有数千行,并且hostname
上的索引是唯一的。规则或触发器应实现一个约束,该约束删除引用已删除计算机的software
中的行。触发器将使用此命令
DELETE FROM software WHERE hostname = $1;
由于触发器针对从computer
删除的每个单独行调用,因此它可以准备并保存此命令的计划,并在参数中传递hostname
值。规则将编写为
CREATE RULE computer_del AS ON DELETE TO computer DO DELETE FROM software WHERE hostname = OLD.hostname;
现在我们来看不同类型的删除。在以下情况下
DELETE FROM computer WHERE hostname = 'mypc.local.net';
表computer
通过索引扫描(快速),并且触发器发出的命令也将使用索引扫描(也很快)。规则发出的额外命令将是
DELETE FROM software WHERE computer.hostname = 'mypc.local.net' AND software.hostname = computer.hostname;
由于设置了适当的索引,因此计划程序将创建以下计划
Nestloop -> Index Scan using comp_hostidx on computer -> Index Scan using soft_hostidx on software
因此,触发器和规则实现之间的速度差异不会很大。
对于下一个删除,我们希望删除所有2000台hostname
以old
开头的计算机。为此,有两个可能的命令。一个是
DELETE FROM computer WHERE hostname >= 'old' AND hostname < 'ole'
规则添加的命令将是
DELETE FROM software WHERE computer.hostname >= 'old' AND computer.hostname < 'ole' AND software.hostname = computer.hostname;
计划为
Hash Join -> Seq Scan on software -> Hash -> Index Scan using comp_hostidx on computer
另一个可能的命令是
DELETE FROM computer WHERE hostname ~ '^old';
这导致规则添加的命令执行以下计划
Nestloop -> Index Scan using comp_hostidx on computer -> Index Scan using soft_hostidx on software
这表明,当将多个限定表达式与AND
组合时,计划程序没有意识到computer
中hostname
的限定条件也可以用于software
上的索引扫描,这正是它在命令的正则表达式版本中所做的。触发器将针对必须删除的每个2000台旧计算机调用一次,这将导致对computer
进行一次索引扫描,对software
进行2000次索引扫描。规则实现将使用两个使用索引的命令来完成它。它取决于software
表的整体大小,规则在顺序扫描情况下是否仍然更快。即使所有索引块很快就会进入缓存,触发器通过SPI管理器执行2000次命令也会花费一些时间。
我们看到的最后一个命令是
DELETE FROM computer WHERE manufacturer = 'bim';
同样,这可能导致从computer
删除许多行。因此,触发器将再次通过执行器运行许多命令。规则生成的命令将是
DELETE FROM software WHERE computer.manufacturer = 'bim' AND software.hostname = computer.hostname;
该命令的计划将再次是两个索引扫描上的嵌套循环,只是使用computer
上的不同索引
Nestloop -> Index Scan using comp_manufidx on computer -> Index Scan using soft_hostidx on software
在任何这些情况下,规则系统发出的额外命令或多或少独立于命令中受影响的行数。
总结一下,只有当规则的操作导致大型且限定性差的联接(计划程序失败的情况)时,规则才会比触发器慢得多。
如果您在文档中看到任何不正确的内容、与您对特定功能的体验不符的内容或需要进一步澄清的内容,请使用此表单报告文档问题。