Question

I am using function to update to one column , like

DetailedStatus = dbo.fn_GetProcessStageWiseStatus(PR.ProcessID, PR.ProcessRunID, getdate()) 

Here 500,000 records are continuously UPDATED in this line. Its like like a loop

So using this function for few records its executing fast but when its 500,000 records executing it becomes very slow...

What can I do to make this execute faster using many records?

Any measures to be taken or any split to be used?

Function:

             CREATE FUNCTION [dbo].[fn_GetProcessStageWiseStatus]    
       (    
       @ProcessID INT    
        ,@ProcessRunID INT    
        ,@SearchDate SMALLDATETIME    
       )    
          RETURNS VARCHAR(100)    
         AS    

      BEGIN    
         DECLARE      
             @iLoopCount SMALLINT    
            ,@iRowCount SMALLINT    
            ,@StepProgress VARCHAR(100)    
            ,@StepCount SMALLINT    

     IF EXISTS(    
              SELECT TOP 1 1    
              FROM dbo.Step S WITH(NOLOCK)    
              JOIN dbo.vw_FileGroup FG    
                    ON S.FileConfigGroupID = FG.FileConfigGroupID    
              WHERE S.ProcessID = @ProcessID    
              AND S.Active = 1    
              AND FG.FileConfigGroupActive = 1    
              AND FG.Direction = 'Inbound'    
              )    
  BEGIN    
        SET @StepProgress = 'Not Received'    
  END    
  ELSE    
  BEGIN    
        SET @StepProgress = 'Not Started'    
  END    

  DECLARE @StepRunDetailsTable TABLE    
  (    
        KeyNo INT IDENTITY(1,1)    
        ,StepID INT    
        ,StepStartTime SMALLDATETIME    
        ,StepEndTime SMALLDATETIME    
        ,SourceEnv VARCHAR(100)    
        ,DestEnv VARCHAR(100)    
  )    

  INSERT INTO @StepRunDetailsTable     
  SELECT    
        S.StepID    
        ,MAX(isnull(SR.StepStartTime, '06/06/2079'))    
        ,MAX(isnull(SR.StepEndTime, '06/06/2079'))    
        ,isnull(SENV.EnvironmentName, '')    
        ,isnull(DENV.EnvironmentName, '')    
  FROM dbo.ProcessRun PR WITH(NOLOCK)    
  JOIN dbo.StepRun SR WITH(NOLOCK)    
        ON SR.ProcessRunID = PR.ProcessRunID    
  JOIN dbo.vw_StepHierarchy SH    
        ON SR.StepID = SH.StepID    
        AND SH.Active = 1    
  JOIN dbo.Step S WITH(NOLOCK)    
        ON SH.StepID = S.StepID    
  JOIN dbo.WorkFlow WF WITH(NOLOCK)    
        ON S.WorkFlowID = WF.WorkFlowID    
        AND WF.Active = 1           
  JOIN dbo.Environment SENV WITH(NOLOCK)    
        ON SENV.EnvironmentID = WF.SourceEnvironmentID    
        AND SENV.Active = 1               
  JOIN dbo.Environment DENV WITH(NOLOCK)    
        ON DENV.EnvironmentID = WF.DestinationEnvironmentID    
        AND DENV.Active = 1    
  WHERE PR.ProcessRunID = @ProcessRunID    
  GROUP BY S.StepID, SENV.EnvironmentName, DENV.EnvironmentName, SH.StepOrder    
  ORDER BY SH.StepOrder ASC    

  SELECT @StepCount = COUNT(*)    
  FROM dbo.ProcessRun PR WITH(NOLOCK)    
  JOIN dbo.Step S WITH(NOLOCK)    
        ON PR.ProcessID = S.ProcessID    
        AND PR.ProcessRunID = @ProcessRunID    
        AND S.Active = 1    

  SELECT @iRowCount = COUNT(DISTINCT StepID) FROM @StepRunDetailsTable    

  SET @iLoopCount = 0      

  WHILE (@iRowCount > @iLoopCount)      
  BEGIN      
        SET @iLoopCount = @iLoopCount + 1    

        SELECT    
              @StepProgress =     
                    CASE    
                          --WHEN @SearchDate BETWEEN StepStartTime AND StepEndTime     
                          WHEN @SearchDate >= StepStartTime AND  @SearchDate <= StepEndTime     
                                THEN DestEnv + ' Load in Progress'    
                          WHEN @SearchDate > StepEndTime AND @iLoopCount < @StepCount    
                                THEN 'Waiting on next step - Loaded to ' + DestEnv    
                          WHEN @SearchDate > StepEndTime AND @iLoopCount = @StepCount    
                                THEN 'Completed'    
                          WHEN @SearchDate < StepStartTime AND @iLoopCount = 1    
                                THEN 'Load Not Started'    
                          ELSE @StepProgress    
              END    

        FROM @StepRunDetailsTable    
        WHERE KeyNo = @iLoopCount    
  END    

  RETURN @StepProgress        

END

Thanks in advance.

Was it helpful?

Solution

Seems like you have a change in execution plan when you try to update 500k rows. You can try and set forceseek hint on the from clause to force using seeks instead of scans.

Also, WHILE (@iRowCount > @iLoopCount) should be replaced with if exists, because you basically check for certain conditions on the results table and you need to return as early as possible.

I see that you use nolock hint everywhere to allow dirty reads, you can set isolation level read uncommitted in the calling stored procedure and remove all of those; or consider to change the database to set read_committed_snapshot on to avoid locks.

By the way, scalar function calls in SQL Server are very expensive, so if you have some massive updates/selects happening in a loop where you call a function you have to avoid using functions as much as possible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top