Reputation: 77
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.
Upvotes: 0
Views: 2236
Reputation: 6015
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.
Upvotes: 1