I have the following code extremely slow code in a MS SQL 2016 Stored Procedure (I think it is stuck in a never ending loop):
@DBID Integer
AS
BEGIN
DECLARE TagCursor CURSOR FOR SELECT MemberID
FROM ADMIN_API_Master_Members_List
WHERE DBID= @DBID AND Len(Pending) > 0
DECLARE @ProgramCode VARCHAR(10)
DECLARE @Values VARCHAR(MAX)
DECLARE @tag nvarchar(10)
OPEN TagCursor
FETCH NEXT FROM TagCursor INTO @tag
WHILE (@@FETCH_STATUS = 0)
BEGIN
SELECT @ProgramCode = Program_Code, @Values= Pending FROM ADMIN_API_Master_Members_List WHERE MemberID= @tag
DELETE FROM ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE
WHERE (MemberID =@tag)
INSERT INTO ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE ( ProgramCode, MemberID, DBID, PMID)
SELECT @ProgramCode, @tag, @DBID , Value FROM STRING_SPLIT(@Values, ',')
END
CLOSE TagCursor
DEALLOCATE TagCursor
END
This Procedure is only a maintenance process and does not get run very often but when it does it would be nice to only take a few seconds. The purpose is to normalize in a Table one record for each comma seperated value in the ADMIN_API_Master_Members_List Table and put it into the ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE with the Program_Code and MemberID and DBID.
There are only about 150 records in the Master Table and the comma separated strings may have 5 values. I am receptive to other solutions.
Thanks in advance
答案 0 :(得分:1)
The reason for the infinite loop may be that you have no "Fetch next" inside your loop Try the below:
@DBID Integer
AS
BEGIN
DECLARE TagCursor CURSOR FOR SELECT MemberID
FROM ADMIN_API_Master_Members_List
WHERE DBID= @DBID AND Len(Pending) > 0
DECLARE @ProgramCode VARCHAR(10)
DECLARE @Values VARCHAR(MAX)
DECLARE @tag nvarchar(10)
OPEN TagCursor
FETCH NEXT FROM TagCursor INTO @tag
WHILE (@@FETCH_STATUS = 0)
BEGIN
SELECT @ProgramCode = Program_Code, @Values= Pending FROM ADMIN_API_Master_Members_List WHERE MemberID= @tag
DELETE FROM ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE
WHERE (MemberID =@tag)
INSERT INTO ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE ( ProgramCode, MemberID, DBID, PMID)
SELECT @ProgramCode, @tag, @DBID , Value FROM STRING_SPLIT(@Values, ',')
FETCH NEXT FROM TagCursor INTO @tag
END
CLOSE TagCursor
DEALLOCATE TagCursor
END
答案 1 :(得分:1)
I haven't tested this, but like I mentioned in the comments, using a CURSOR
is a bad idea; they are inherently slow as SQL Server excels at set based methods not iterative tasks (and a CURSOR
is the latter).
I suspect that this achieves the answer you're after and avoids the CURSOR
all together:
CREATE PROC YourProc @DBID integer
AS
BEGIN
DECLARE @Deleted table (ProgramCode varchar(10),
[Value] varchar(MAX),
Tag nvarchar(10));
DELETE HT
OUTPUT deleted.Program_Code,
deleted.Pending,
deleted.MemberID
INTO @Deleted (ProgramCode,
[Value],
Tag)
FROM ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE AS HT
JOIN ADMIN_API_Master_Members_List AS MML ON HT.MemberID = MML.MemberID
WHERE MML.[DBID] = @DBID
--AND LEN(Pending) > 0; --Changed this to below to be SARGable, as only a string with the value '' will have a length of 0.
AND Pending != '';
INSERT INTO ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE (ProgramCode,
MemberID,
DBID,
PMID)
SELECT D.ProgramCode,
D.Tag,
@DBID,
SS.Value
FROM @Deleted AS D
CROSS APPLY STRING_SPLIT(D.[Value], ',') AS SS;
END;