1

我有一个数据库清除过程,它使用存储过程从基于 的巨大表中删除记录Expire Date,它每 3 周运行一次并删除大约 300 万条记录。

目前清除数据大约需要 5 个小时,这会导致很多问题。我知道有很多有效的方法来编写代码,但是我没有想法,请帮助我找到正确的方向。

--Stored Procedure
CREATE PROCEDURE [dbo].[pa_Expire_StoredValue_By_Date]
     @ExpireDate DateTime, @NumExpired int OUTPUT, @RunAgain int OUTPUT 
AS
   -- This procedure expires all the StoredValue records that have an ExpireDate less than or equal to the DeleteDate provided
   -- and have QtyUsed<QtyEarned
   -- invoked by DBPurgeAgent

   declare @NumRows int  

   set nocount on  
   BEGIN TRY    
     BEGIN TRAN T1  

        set @RunAgain = 1;  
        select @NumRows = count(*) from StoredValue where ExpireACK = 1;  

        if @NumRows = 0 
        begin  
           set rowcount 1800;  -- only delete 1800 records at a time  

           update StoredValue with (RowLock) 
           set ExpireACK = 1 
           where ExpireACK = 0 
             and ExpireDate < @ExpireDate 
             and QtyEarned > QtyUsed;  

           set @NumExpired=@@RowCount;  
           set rowcount 0  
        end  
        else begin  
           set @NumExpired = @NumRows;  
        end  

        if @NumExpired = 0 
        begin  -- stop processing when there are no rows left  
           set @RunAgain = 0;  
        end  
        else begin  
            Insert into SVHistory (LocalID, ServerSerial, SVProgramID, CustomerPK, QtyUsed, Value, ExternalID, StatusFlag, LastUpdate, LastLocationID, ExpireDate, TotalValueEarned, RedeemedValue, BreakageValue, PresentedCustomerID, PresentedCardTypeID, ResolvedCustomerID, HHID)  
                select 
                   SV.LocalID, SV.ServerSerial, SV.SVProgramID, SV.CustomerPK, 
                   (SV.QtyEarned-SV.QtyUsed) as QtyUsed, SV.Value, SV.ExternalID, 
                   3 as StatusFlag, getdate() as LastUpdate, 
                   -9 as LocationID, SV.ExpireDate, SV.TotalValueEarned, 
                   0 as RedeemedValue, 
                   ((SV.QtyEarned-SV.QtyUsed)*SV.Value*isnull(SVUOM.UnitOfMeasureLimit, 1)), 
                   PresentedCustomerID, PresentedCardTypeID, 
                   ResolvedCustomerID, HHID   
                from 
                   StoredValue as SV with (NoLock) 
                Left Join 
                   SVUnitOfMeasureLimits as SVUOM on SV.SVProgramID = SVUOM.SVProgramID  
                where 
                   SV.ExpireACK = 1  

           Delete from StoredValue with (RowLock) where ExpireACK = 1;  
        end  

        COMMIT TRAN T1;  
    END TRY  
    BEGIN CATCH  
       set @RunAgain = 0;  

       IF @@TRANCOUNT > 0 BEGIN  
          ROLLBACK TRAN T1;  
       END  

       DECLARE @ErrorMessage NVARCHAR(4000);  
       DECLARE @ErrorSeverity INT;  
       DECLARE @ErrorState INT;  

       SELECT 
           @ErrorMessage = ERROR_MESSAGE(), 
           @ErrorSeverity = ERROR_SEVERITY(), 
           @ErrorState = ERROR_STATE();  

       RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);  
    END CATCH
4

2 回答 2

1

为什么你以这种逻辑运行对我来说毫无意义。看起来您正在通过一遍又一遍地重新运行存储的过程来进行批处理。您真的应该在一个WHILE循环中执行它并在存储过程的一次运行中使用较小的批次。您还应该在较小的事务中运行,这将大大加快速度。可以说,这种编写方式不需要事务。您可以恢复,因为您正在标记每条记录。

也不清楚你为什么要触摸桌子 3 次。您真的不需要更新标志并将行选择到新表中然后删除它们。如果需要,您可以在一个步骤中使用输出子句来执行此操作,但您需要澄清您的逻辑以获得帮助。

另外,你为什么用ROWLOCK?锁升级很好,可以让事情运行得更快(更少的内存持有锁)。您是否在系统运行时运行此程序?如果是下班后,请TABLOCK改用。

这是一些您可以充实的建议伪代码。我建议将@BatchSize 作为参数。显然还缺少错误处理,这只是删除逻辑的核心。

WHILE 1=1
BEGIN
    BEGIN TRAN

    UPDATE TOP (@BatchSize) StoredValue
    SET <whatever>

    INSERT INTO SVHistory <insert statement>

    DELETE FROM StoredValue WHERE ExpireAck=1

    IF @@ROWCOUNT = 0
    BEGIN
        COMMIT TRAN
        BREAK;
    END

    COMMIT TRAN

END
于 2013-07-15T14:00:43.857 回答
0

首先通过查看执行计划来查看导致它变慢的原因。是插入语句还是删除?

由于插入中的计算,我怀疑它是较慢的部分(除非您在表上有触发器或级联删除)。您可以更改历史表以包含您在计算中使用的列,并在计算字段中允许空值。现在您可以更快地插入该表,然后执行删除。然后,您可以在工作的一个单独步骤中更新计算。这至少会在更短的时间内将事情捆绑起来,但取决于历史表的访问方式可能会也可能不会。

另一种开箱即用的可能性是将表 StoredValue 重命名为 StoredValueRaw 并创建一个名为 StoredValue 的视图,该视图仅显示活动记录。然后删除记录的作业可以每十五分钟左右运行一次,一次只删除几条记录。即使实际删除需要更长的时间,这对用户的破坏性也可能要小得多。您可能仍然需要在记录被识别为过期时将它们放入历史记录表中。

您可能还应该重新考虑每三周执行一次此过程,您必须处理的记录越少,处理速度就越快。

于 2013-07-15T14:29:07.513 回答