AFTER UPDATE 触发器中 UPDATE 的性能问题

Performance issues with UPDATE in AFTER UPDATE Trigger

我的 MS-SQL Server 2014 数据库中的一个数据库触发器有一个小的性能问题。

CREATE TRIGGER [dbo].[TRG_T_TPM_Vehicle_Update] ON [dbo].[T_TPM_Vehicle]
   AFTER UPDATE
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
UPDATE T_TPM_Vehicle SET LastUpdated = getdate() 
       WHERE Vehicle_Number IN (SELECT Vehicle_Number FROM inserted)

UPDATE T_TPM_Vehicle SET [DisturbedSince] = getdate() 
       WHERE Vehicle_Number IN (SELECT Vehicle_Number FROM inserted WHERE inserted.Emergency_Stop = 1)
         AND Vehicle_Number IN (SELECT Vehicle_Number FROM deleted WHERE deleted.Emergency_Stop = 0)

INSERT INTO T_TPM_Vehicle_HistoricalData
       ([Vehicle_Ref]
       ,[Vehicle_Number]
       ,[Vehicle_Type]
       ,[Pos_X]
       ,[Pos_Y]
       ,[Alpha]
       ,[LastAutoPos_X]
       ,[LastAutoPos_Y]
       ,[LastAutoAlpha]
       ,[Automatic]
       ,[Manual]
       ,[Blocked]
       ,[Loaded]
       ,[Stoped]
       ,[Emergency_Stop]
       ,[User_Required]
       ,[BatteryAlmostEmpty]
       ,[BatteryEmpty]
       ,[BatteryLevel]
       ,[ChargingRelaisEnable]
       ,[NavOK]
       ,[PowerOn]
       ,[Available]
       ,[OperatingMinutes]
       ,[UpdateOperatingMinutes]
       ,[DataChangedByVIS]
       ,[Blockingsreleased]
       ,[Cancelled]
       ,[ProductID]
       ,[HUIdent1]
       ,[HUIdent2]
       ,[HUType]
       ,[DisturbedSince])
 SELECT inserted.[Vehicle_Ref]
  ,inserted.[Vehicle_Number]
  ,inserted.[Vehicle_Type]
  ,inserted.[Pos_X]
  ,inserted.[Pos_Y]
  ,inserted.[Alpha]
  ,inserted.[LastAutoPos_X]
  ,inserted.[LastAutoPos_Y]
  ,inserted.[LastAutoAlpha]
  ,inserted.[Automatic]
  ,inserted.[Manual]
  ,inserted.[Blocked]
  ,inserted.[Loaded]
  ,inserted.[Stoped]
  ,inserted.[Emergency_Stop]
  ,inserted.[User_Required]
  ,inserted.[BatteryAlmostEmpty]
  ,inserted.[BatteryEmpty]
  ,inserted.[BatteryLevel]
  ,inserted.[ChargingRelaisEnable]
  ,inserted.[NavOK]
  ,inserted.[PowerOn]
  ,inserted.[Available]
  ,inserted.[OperatingMinutes]
  ,inserted.[UpdateOperatingMinutes]
  ,inserted.[DataChangedByVIS]
  ,inserted.[Blockingsreleased]
  ,inserted.[Cancelled]
  ,inserted.[ProductID]
  ,inserted.[HUIdent1]
  ,inserted.[HUIdent2]
  ,inserted.[HUType]
  ,inserted.[DisturbedSince] 
FROM inserted
END

它基本上做的是为插入的所有行设置 LastUpdated 列,为插入行的子集设置 DisturbedSince 列。

最后,插入的行被复制到历史记录中 table。 (任何行的每次更改都必须保存两天)。旧数据被维护作业删除。

因为我们每秒更新多达 300 行(对行的更新可以一起批处理)我们创建了大量数据和递归更新。

我现在找到了 INSTEAD OF UPDATE 触发器,它似乎解决了由我的触发器引起的递归更新问题,但我必须用更新语句逐行处理插入的 table 的每一行在触发器中。

我不确定这是否真的更快。大家有推荐的吗?

我真正需要的是在将数据行发送到 table 之前调整/扩展数据行。有解决办法吗?

例如:类似:

CREATE TRIGGER ... INSTEAD OF UPDATE
AS
BEGIN
    UPDATE inserted SET LastUpdated = getdate()
    UPDATE inserted SET DisturbedSince 
     WHERE Vehicle_Number IN (SELECT Vehicle_Number FROM inserted WHERE inserted.Emergency_Stop = 1)
       AND Vehicle_Number IN (SELECT Vehicle_Number FROM deleted WHERE deleted.Emergency_Stop = 0)
    "SAVE INSERTED"
END

和一个更新后触发器,将更改的数据存储到历史记录中 table。

感谢您的任何建议。

托马斯

当您想要在同一个 [=28] 中更改数据时,您认为使用 INSTEAD OF 触发器而不是 AFTER 触发器是正确的方法是正确的=] 还有。

它会是这样的:

CREATE TRIGGER [dbo].[TRG_T_TPM_Vehicle_Update] ON [dbo].[T_TPM_Vehicle]
   INSTEAD OF UPDATE
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

UPDATE tgt
SET
   Vehicle_Ref = i.Vehicle_Ref,
   Vehicle_Type = i.Vehicle_Type,
   ...
   LastUpdated = getdate(),
   DisturbedSince = CASE WHEN i.Emergency_Stop=1 and d.Emergency_Stop=0
                    THEN getdate() ELSE d.DisturbedSince END
OUTPUT
   inserted.[Vehicle_Ref]
  ,inserted.[Vehicle_Number]
  ,inserted.[Vehicle_Type]
  ...
  ,inserted.[HUIdent2]
  ,inserted.[HUType]
  ,inserted.[DisturbedSince] 
INTO T_TPM_Vehicle_HistoricalData
       ([Vehicle_Ref]
       ,[Vehicle_Number]
       ,[Vehicle_Type]
       ...
       ,[HUIdent2]
       ,[HUType]
       ,[DisturbedSince])
FROM
   T_TPM_Vehcile tgt
      inner join
   inserted i
      on
         tgt.Vehicle_Number = i.Vehicle_Number
      inner join
   deleted d
      on
         tgt.Vehicle_Number = d.Vehicle_Number

您会注意到,我已将 UPDATEINSERT 合并到历史 table 中,形成一个复合语句。

您还会注意到它有点令人困惑,因为这里有两个 inserteds - inserted 作为触发器的一部分(别名为 i 以回避一些混淆)和 inserted 作为 OUTPUT 子句的一部分。