1

我尝试优化我的一些处理。我有两个表(Job 和 Bucket),它们都具有我想要同步的状态。即如果有人更改了作业的状态,那么有时我会更改存储桶的状态,有时当我更改存储桶的状态时,我想更改附加作业的状态。有时在这方面主要意味着“取消”,但也意味着从作业流向存储桶的完成/错误。

它们有 2 个状态的原因是(a)它们是独立的子系统,例如可以暂停作业,以及(b)并非每个作业都附加到存储桶;)

我尝试使用 2 个触发器来执行此操作 - 一个在作业上更新,一个在存储桶上更新,但似乎每当作业上的触发器更改存储桶时,存储桶上的触发器就会触发。好笑的是,虽然这是一个更新后的触发器,但似乎触发器并没有看到另一个表中的变化......这导致了递归。

触发器是:

ALTER TRIGGER [grd].[Job_UpdateBucket]
   ON  [grd].[Job]
   AFTER UPDATE
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    UPDATE
        [simstg].[Bucket]
    SET
        [Status] = i.[Status],
        [StatusTimestamp] = GETUTCDATE()
    FROM
        [simstg].[Bucket] b
        JOIN [inserted] i ON (b.[JobRef] = i.[Id])
    WHERE
        i.[Status] IN ('C', 'F', 'X', 'A')
        AND b.[Status] <> i.[Status]
        AND b.[Status] NOT IN ('X')

END

ALTER TRIGGER [simstg].[Bucket_UpdateJob] 
   ON  [simstg].[Bucket]
   AFTER UPDATE
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    UPDATE
        [grd].[Job]
    SET
        [Status] = 'X',
        [LastUpdate] = GETUTCDATE()
    FROM
        [grd].[Job] j
        JOIN [inserted] i ON (j.Id = i.JobRef)
    WHERE
        i.[Status] = 'X'
        AND j.[Status] <> i.[Status]

END

这是 - 虽然我做 SQL 很长时间 - 我第一次有这种类型或递归。我认为where条件可以避免递归,因为它是一个AFTER触发器,所以如果Job更新bucket,bucket触发器应该看到job中已经改变的状态,所以应该没有递归。

这导致两个问题:

1:我错了吗?如果我更新 Job,那么触发器会更改 Bucket,那么 Bucket 上的触发器应该会看到 Job 中更改的数据,还是?由于比较状态与新状态不同的 WHERE 条件,这应该可以避免递归。

2:这里有什么其他方法可以避免递归吗?

4

1 回答 1

2

这是记录在案的行为。文档状态

这些触发器在任何有效事件被触发时触发,无论是否有任何表行受到影响。

因此,即使您使用 where 子句确保更新中没有行受到影响,更新仍然会触发触发器,依此类推。我建议管理此问题的最佳方法是使用TRIGGER_NESTLEVEL找出您所处的递归级别,例如

ALTER TRIGGER [simstg].[Bucket_UpdateJob] 
   ON  [simstg].[Bucket]
   AFTER UPDATE
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- CHECK TRIGGER NEST LEVEL HERE AND EXIT IF TOO HIGH
    IF TRIGGER_NESTLEVEL() > 1
        RETURN;

    UPDATE
        [grd].[Job]
    SET
        [Status] = 'X',
        [LastUpdate] = GETUTCDATE()
    FROM
        [grd].[Job] j
        JOIN [inserted] i ON (j.Id = i.JobRef)
    WHERE
        i.[Status] = 'X'
        AND j.[Status] <> i.[Status]

END

另一种选择是使用该UPDATE()函数Status在运行更新之前查看列是否已更新,或者更详细,在执行更新之前检查行是否会受到影响:

ALTER TRIGGER [simstg].[Bucket_UpdateJob] 
   ON  [simstg].[Bucket]
   AFTER UPDATE
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    IF EXISTS (SELECT 1 FROM inserted)
    BEGIN
        UPDATE
            [grd].[Job]
        SET
            [Status] = 'X',
            [LastUpdate] = GETUTCDATE()
        FROM
            [grd].[Job] j
            JOIN [inserted] i ON (j.Id = i.JobRef)
        WHERE
            i.[Status] = 'X'
            AND j.[Status] <> i.[Status]
    END

END
于 2014-05-28T15:37:44.433 回答