代码之家  ›  专栏  ›  技术社区  ›  James Black

如何重构使用插入和删除的表的触发器,以将公共代码移动到存储过程

  •  2
  • James Black  · 技术社区  · 15 年前

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

    触发器大约有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 回复  |  直到 15 年前
        1
  •  4
  •   Remus Rusanu    15 年前

    这实际上是个坏主意。SQL不像是您运行的工厂程序语言。SQL“compilation”绑定到物理访问路径计划,这意味着语句被编译成“open rowset with id 1234,seek a record and retrieve its content”计划,并且“1234”是在 汇编 由优化器进行批处理。这意味着,在您计划的过程中,将公共代码移动到过程中所带来的伤害往往大于它所带来的好处。该过程不能绑定到“通用”访问路径,它需要知道它应该查找的用于选择和更新等的实际表和对象。您要么最终在过程中执行动态SQL,要么只移动过程的非数据绑定、通用部分(如计算),这些部分会创建非常复杂的代码,同时还会损害性能 递减 程序可读性。

    更明智的做法是使用模板,并通过各种代码生成技术(如XML和XSLT)从这些模板生成触发器。

        2
  •  0
  •   Cade Roux    15 年前

    我怀疑元数据/模式 inserted deleted 这里的核心问题是(这就是为什么你要使用 SELECT * INTO )

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

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

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