触发器中的更新语句执行时间比在触发器外执行时要长

时间:2012-08-30 01:41:48

标签: sql tsql sql-server-2005

我有After Update

的触发器

此触发器适用于将在链接服务器上更新2个表的服务器

参见代码

ALTER TRIGGER [dbo].[tgAfterUpdate] ON  [dbo].[KS_3EToVision]
   AFTER UPDATE
AS 
BEGIN

  BEGIN TRY
  BEGIN TRANSACTION    -- Start the transaction

  DECLARE @MatterNumber varchar(15);
  SELECT @MatterNumber = i.MatterNumber FROM inserted i; 

    IF EXISTS(SELECT * FROM [FSSQLDEV01].[collnab].[dbo].[collection_header] WHERE         Ch_file_number COLLATE DATABASE_DEFAULT = @MatterNumber COLLATE DATABASE_DEFAULT)
       --UPDATE
        IF (SELECT Ch_matter_status FROM [FSSQLDEV01].[collnab].[dbo].[collection_header] WHERE Ch_file_number COLLATE DATABASE_DEFAULT = @MatterNumber COLLATE DATABASE_DEFAULT ) = 'Current'
             BEGIN 
                --Parent table 
                UPDATE [FSSQLDEV01].[collnab].[dbo].[collection_header]
                SET 
                    Ch_start_date = i.OpenDate 
                FROM 
                    Inserted i 
                WHERE ch_file_number COLLATE DATABASE_DEFAULT = @MatterNumber COLLATE DATABASE_DEFAULT  

                ----Child table 
                UPDATE [FSSQLDEV01].[collnab].[dbo].[collections] 
                SET 
                    Defendant_1 = i.Description 
                    , Loan_Number_1 = i.Comments 
                    , Client = i.KS_BookName 
                    , Date_Instructed = i.OpenDate 
                    , Person_Responsible_name = i.ResponsibleFeeEarnerName 
                    , Person_Responsible_Email = i.ResponsibleFeeEarnerEmail 
                    , Person_Acting_name = i.BillingFeeEarnerName 
                    , Person_Acting_email = i.BillingFeeEarnerEmail 
                    , Agent_Acting_name = i.BillingFeeEarnerName 
                    , Agent_Acting_email = i.BillingFeeEarnerEmail 
                    , CBA_Panel_Service_Area = i.KS_ServiceCat 
                    , HBN_Number = i.KS_ClientAcctRef 
                    , St_George_Contact = i.KS_Instructor 
                FROM 
                    Inserted i 
                WHERE Left(Collections.file_number,6) COLLATE DATABASE_DEFAULT = @MatterNumber COLLATE DATABASE_DEFAULT
             END

--If we reach here, success!
   COMMIT
END TRY
BEGIN CATCH
  -- Whoops, there was an error
  IF @@TRANCOUNT > 0
     ROLLBACK

  -- Raise an error with the details of the exception
  DECLARE @ErrMsg nvarchar(4000), @ErrSeverity int
  SELECT @ErrMsg = ERROR_MESSAGE(),
     @ErrSeverity = ERROR_SEVERITY()

  RAISERROR(@ErrMsg, @ErrSeverity, 1)
END CATCH

END 

如果我尝试使用触发器之外的相同条件的更新语句,它只需要1秒钟,但在触发器内部最多可能需要45秒。

我已将其缩小到第二个更新语句是问题,因为如果我删除第二个更新语句,它将快速执行。

我还附上了一个图片

我还有一个Trigger for Insert,它可以在一秒内快速完成,而且一个用于删除,这将在触发器中延长一段时间但如果我删除触发器之外的2个删除语句,则运行正常。

USE [TE_3E_TRG]
GO
/****** Object:  Trigger [dbo].[tgAfterDelete]    Script Date: 08/30/2012 11:24:33 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dbo].[tgAfterDelete] ON  [dbo].[KS_3EToVision]
   AFTER DELETE
AS 

begin

BEGIN TRY
   BEGIN TRANSACTION    -- Start the transaction
            Begin
                --Parent table 
                DELETE FROM [FSSQLDEV01].[collnab].[dbo].[collection_header] WHERE ch_file_number COLLATE DATABASE_DEFAULT = (SELECT d.MatterNumber FROM deleted  d) COLLATE DATABASE_DEFAULT

                --Child table 
                DELETE FROM [FSSQLDEV01].[collnab].[dbo].[collections] WHERE Left(file_number,6) COLLATE DATABASE_DEFAULT = (SELECT d.MatterNumber FROM deleted  d) COLLATE DATABASE_DEFAULT            

            END
   -- If we reach here, success!
   COMMIT
END TRY
BEGIN CATCH
  -- Whoops, there was an error
  IF @@TRANCOUNT > 0
     ROLLBACK

  -- Raise an error with the details of the exception
  DECLARE @ErrMsg nvarchar(4000), @ErrSeverity int
  SELECT @ErrMsg = ERROR_MESSAGE(),
         @ErrSeverity = ERROR_SEVERITY()

  RAISERROR(@ErrMsg, @ErrSeverity, 1)
END CATCH

有谁知道为什么在执行触发器内的语句和触发器的外侧之间可能会出现执行时间的巨大差异?

1 个答案:

答案 0 :(得分:0)

您正在使用本地虚拟插入表加入远程表。这可能涉及将整个表从远程服务器复制到本地并在本地过滤。

这是非常罕见的情况,使用游标和逐行更新可能会提高性能。

BTW marc_s的观点是正确的,你的代码应该考虑插入表有多于一行的可能性。