我们可以用存储过程替换DML触发器吗?

时间:2015-12-17 14:20:49

标签: sql-server tsql

在输入标题文字时,不确定是否在原因之前询问过这个问题,可能重复的给定建议并不匹配。

我的一位同事询问是否可以使用存储过程(SP)完全替换DML触发器功能。听起来有点奇怪,但它可能导致触发器也是一种特殊类型的SP,但不能明确地调用。

我的意思是说例如:在AFTER INSERT Trigger上定义的名为trg_insert1的{​​{1}}确实更新了tbl1中的某些数据,如下所示(采用SQL Server示例但问题并不特定于任何DB)

tbl2

现在可以用下面的SP替换此触发器(使用事务块);

create trigger trg_insert1 
after insert on tbl1
foreach row
begin

update tbl2 set somedata = inserted.tbl1somedata
where id = inserted.tbl1id;

end

几乎在所有DML触发器的情况下都能完美地工作,比如之后/之前 - >插入/删除/更新。但我真的无法回答/解释

那有什么不同呢?

这样做是否是一种好习惯?

在所有情况下都不可能吗?

我是否认为它过于复杂。

请让我知道你的想法。

[注意:虽然不是特定的RDBMS相关问题]

2 个答案:

答案 0 :(得分:2)

我会尝试以非常一般的方式回答(您指定这不是针对特定实现的。)

首先,触发器使用与存储过程相同的数据操作语言编写。因此,在功能方面,触发器和存储过程是相同的。

但是...

无论您是通过存储过程,另一个触发器还是手动执行SQL语句,都可以保证在每次更改数据时都会调用触发器。 实际上,除非您明确禁用,否则您可以期望触发总是执行(对于其触发语句)

另一方面,存储过程保证永远不会自行运行 ,除非您明确地运行它

这有一个重要的结果:触发器可以更好地确保一致性。如果有人匆忙通过键入以下内容删除了您的实时实例中的记录:

Delete from tablex where uid="QWTY10311"

任何作为触发器执行的簿记操作都将被执行,而如果用户忘记(或恶意避免)跟随此

 Execute SP_TABLEX_LOG("DELETE","QWTY10311") 

您的数据库将以静默方式丢失数据。

触发器还有另外两个重要的特性,只有通过额外的(有时显着更昂贵的)努力才能与存储过程重复。

首先,他们按记录逐项执行。因此,如果要删除100万条记录,则将对每个操作执行日志记录。祝你用100万行光标作为参数调用适当的存储过程,特别是如果你想在手动操作之后这样做,如上例所示。

第二个优势:触发器具有特殊的范围,可以为每个字段引用更改前后的值。 因此,如果您要将价格表增加10%并想要记录之前的值,以及哪个用户在什么时间执行了操作,那么您将拥有"旧值"," new-value"," user-id"和"时间戳"适用于您可能想要进行的任何操作。 同样,通过调用存储过程来执行此操作意味着您必须保存值以在运行时将它们传递给存储过程。

那么为什么还要打扰SP ? (希望你能回答关于"最佳使用案例")的问题。

当您需要创建将由应用程序层调用的复杂业务逻辑时,

存储过程会更好。因此,如果您想知道,例如,在两个给定日期之间有多少酒店房间,并且允许宠物的额外要求,触发器不是一个好主意。 特别是因为触发器不会将任何结果返回给调用进程... 因此,无论何时您需要向调用者获取结果,无论是查询,计算还是具有OUTPUT参数的任何其他内容,触发器都是无用的。

应使用触发器来强制执行一致性。如果不应删除标头记录,除非其他表中没有子节点,可以使用触发器强制执行此操作。如果您需要记录在字段中更改值的人,无论如何,请使用触发器。 在所有其他情况下,使用存储过程(请记住,触发器将影响任何数据更新的响应性,就像索引一样)。

答案 1 :(得分:1)

是的存储过程可以用这种方式替换DML触发器,是否是一种好的做法取决于您的需求。

主要区别在于触发器每次触发时都会运行其代码。在您的示例中,如果用户执行临时INSERTtbl1,则会触发一个触发器,tbl2将会更新。

如果不允许ad-hoc INSERT,则只能使用存储过程来强制执行此规则。