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
您会注意到,我已将 UPDATE
和 INSERT
合并到历史 table 中,形成一个复合语句。
您还会注意到它有点令人困惑,因为这里有两个 inserted
s - inserted
作为触发器的一部分(别名为 i
以回避一些混淆)和 inserted
作为 OUTPUT
子句的一部分。
我的 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
您会注意到,我已将 UPDATE
和 INSERT
合并到历史 table 中,形成一个复合语句。
您还会注意到它有点令人困惑,因为这里有两个 inserted
s - inserted
作为触发器的一部分(别名为 i
以回避一些混淆)和 inserted
作为 OUTPUT
子句的一部分。