如何重构使用inserted和deleted表的触发器,将公共代码移动到存储过程

时间:2009-06-03 01:40:29

标签: sql-server sql-server-2008 stored-procedures refactoring triggers

我有一个动态创建的触发器,因为它将附加到也是动态生成的视图。我不希望我的存储过程在其中包含整个触发器,因此我想将其中的大部分移动到存储过程,但我不知道插入和删除表中的字段。

触发器大约有90行,并且触发器之间唯一真正需要区别的是:

DECLARE @DEBUG bit = 1
DECLARE @EntityName nvarchar(128) = 'Lot'
    SELECT * INTO #MYINSERTED FROM INSERTED
    SELECT * INTO #MYDELETED FROM DELETED

如果我可以将其余部分移动到存储过程,那就太棒了。

只是传入@DEBUG和@EntityName并在存储过程中使用#MYINSERTED和#MYDELETED然后如果两个人同时插入或更新同一个视图,我会遇到问题。

最好的办法是传递一个表变量来删除任何并发问题,但我不确定最好的方法。

谢谢。

2 个答案:

答案 0 :(得分:4)

这实际上是一个坏主意。 SQL不像你的普通程序语言。 SQL'编译'绑定到物理访问路径计划,这意味着语句被编译成计划,表示'打开行集ID 1234,寻找记录并检索其内容',并且'1234'在期间确定优化程序批量编译。这意味着在您计划更频繁地将公共代码移动到过程中会比其受益更多地受到伤害。该过程不能绑定到“通用”访问路径,它需要知道它应该查看的实际表和对象以进行选择和更新等。您要么最终在过程中执行动态SQL,要么只移动非数据绑定,泛型,过程的一部分(例如计算),这会产生非常复杂的代码,但仍会损害性能,同时减少程序可读性。

更可取的是拥有一个模板,并通过各种代码生成技术(如XML和XSLT)从这些模板生成触发器。

答案 1 :(得分:0)

我怀疑关于inserteddeleted的元数据/架构是这里的核心问题(这就是您使用SELECT * INTO的原因)。

如果您是生成触发器并动态查看的代码,我会说它可能没有多大区别。毕竟,所有触发器和视图都是代码生成的,并且可以在系统获得新功能或核心SP得到改进时重新生成。

只有触发器和视图是自定义的并且永远不会重新生成时,共享核心SP才有好处,可以修改和升级,而不是重新生成视图和触发器。

生成的代码可能会超过重新生成的开销,这将有一个可靠的执行计划和更好的绑定。