SQL Server 触发器的性能

a_h*_*ame 1 trigger sql-server-2005

我来自 Oracle/PostgreSQL 背景,很难应对 SQL Server 触发器实现的限制。

datetime如果不同列的值发生变化,我想更新两个不同的列。这是为了记录该行的两个特定状态变化。

现在 SQL Server 既没有行级触发器,也没有before update触发器。所以我的理解是,我需要加入插入和删除以找出是否发生了状态更改以及发生了哪些状态更改,然后对正在更新的表再次运行“常规”更新。

我的触发器目前看起来像这样:

create trigger ord_status_history_trigger
  on jobs
AFTER UPDATE
AS
  IF ( UPDATE(order_status) )
  BEGIN
    update jobs
      set  transfercomplete = case
                                when o.order_status = 'initial' and n.order_status = 'sent' then current_timestamp
                                else n.transfercomplete
                              end,
           installcomplete = case
                               when o.order_status = 'delivered' n.order_status = 'installed' then current_timestamp
                               else n.installcomplete
                            end
      from inserted n
        join deleted o on o.jobid = n.jobid
        join jobs aj on aj.jobid = n.jobid;
  END
Run Code Online (Sandbox Code Playgroud)

我的问题是:这个触发器是否有效地导致了表上的两次更新?

第一个是触发更新,第二个是触发器执行的更新?

或者 SQL Server 是否足够聪明,可以将其合并到对基表的单个更新中(本质上是它BEFORE UPDATE在 PostgreSQL 中使用触发器的方式)

我会在这里创建潜在的性能瓶颈吗?

我们也可以在应用程序中设置这些时间戳,但是如果我们可以将其委托给数据库会更好,这样我们就可以确保永远不会忘记这一点。

Rem*_*anu 5

您的触发器在表上发生更新后运行。如果您在触发器中再次更新表,则会执行新的更新。另见关于RECURSIVE_TRIGGERS的讨论。

如果要在更新之前运行代码,则必须创建INSTEAD OF 触发器

是否必须做两次而不是一次更新会成为瓶颈完全取决于您的触发器中的更新效率,当然,这个UPDATE是否已经在关键路径上。您可能在作业 id 上有一个主键,缓冲池中的页面很热,并且您不能有锁冲突。所以基本上只取决于a)您的日志接受写入的速度有多快以及b)版本存储(为删除和插入的伪表提供服务)是否可以跟上。

如果你问我:这样的业务逻辑状态管理属于应用程序,而不是触发器......

  • INSTEAD OD 触发器是运行*而不是*您的更新的代码。如果您希望发生任何写入,则必须这样做(即在触发器中运行 UPDATE 语句)。如果要访问更改的数据,则必须访问它(即查找插入/删除的伪表)。不知道你在问什么。 (2认同)