I am creating a stored procedure that is used by another program. The procedure is very slow for large databases, and I wanted to see if there are suggestions on making it faster. Each entry in the database has a time stamp, which is not
necessarily unique. Some rows share the same time stamp. I want to get a list of the distinct timestamps for which a list of conditions is true for that time stamp (across multiple rows). I first select data from the database
data to populate a @searchTbl by selecting rows in the table that have either a specific User, Var3, and/or Time (if these are sent to the procedure and so are not NULL). If the user does not send a specific time (If NULL), I get the latest entries for
each unique combination of certain variables (Var4, Var1, Var2, Var3). I then eliminate rows from the @searchTbl by selecting terms from a conditions table (@condTbl) to create a new select statement. For each recursive loop, I put the new
selection into a @loopTbl, then delete from the @searchTbl, then populate the @searchTbl with the @loopTbl data, then delete the @loopTbl data (I know this is embarrassingly inefficient).
Is there a way to accomplish all of this more efficiently without using the @searchTbl and/or @loopTbl? I think this might be why it's so slow, because I have to put nearly the whole database into the @searchTbl to begin.
EDIT NOTE: SEE MY RESPONSE DOWN THE PAGE FOR THE STORED PROCEDURE DDL
The code to create the table types is listed below the procedure code:
Gina
DECLARE @ProjectTable nvarchar(128) SET @ProjectTable = 'RIProj_HCT' DECLARE @CondTbl conditions_tbltype READONLY DECLARE @UserName nvarchar(255) = NULL DECLARE @eTime datetime = NULL DECLARE @Var3 nvarchar(255) = NULL DECLARE @SQL nvarchar(4000) DECLARE @whereAdd nvarchar(4000) DECLARE @Var4 nvarchar(255) DECLARE @Var4Var3Time nvarchar(255) DECLARE @Var1 nvarchar(255) DECLARE @Var2 nvarchar(255) DECLARE @CondSign nvarchar(30) DECLARE @ValType nvarchar(255) DECLARE @VarTxt nvarchar(4000) DECLARE @VarNum float DECLARE @c int DECLARE @condCt int SET @condCt = (SELECT count(*) FROM @CondTbl) DECLARE @SearchTbl tempSearchTbl_tbltype DECLARE @LoopTbl tempSearchTbl_tbltype IF (object_id(@ProjectTable) is NULL) BEGIN RETURN END SET @whereAdd = '' IF @Var3 IS NOT NULL BEGIN SET @whereAdd = @whereAdd + ' AND Var3 = @Var3' END IF @UserName IS NOT NULL BEGIN SET @whereAdd = @whereAdd +' AND UserName = @UserName' END IF @Time IS NOT NULL BEGIN SET @whereAdd = @whereAdd +' AND eTime = @eTime' END ELSE BEGIN SET @whereAdd = @whereAdd +' AND NOT EXISTS (SELECT 1 FROM ' + @ProjectTable + ' WHERE Var4 = p.Var4 AND Var1 = p.Var1 AND Var2 = p.Var2 AND Var3 = p.Var3 AND Time > p.eTime)' END SET @SQL = 'SELECT Var4, UserName, Var3, Var1, VarNum, VarTxt, NForm, Var2, eTime, Var4Var3Time FROM ' + @ProjectTable + ' p WHERE 1 = 1' + @whereAdd INSERT INTO @SearchTbl (Var4, UserName, Var3, Var1, VarNum, VarTxt, NForm, Var2, eTime, Var4Var3Time) EXEC sp_executesql @SQL, N'@Var4 nvarchar(255), @UserName nvarchar(255), @ProjectTable nvarchar(255), @Var3 nvarchar(255)', @Var4, @UserName, @ProjectTable, @Var3 ConditionLoop: IF @condCt >= 1 BEGIN SET @c = 1 WHILE @c <= @condCt BEGIN SET @Var1 = (SELECT Var1 FROM @CondTbl WHERE cID = @c) SET @Var2 = (SELECT Var2 FROM @CondTbl WHERE cID = @c) SET @CondSign = (SELECT condSign FROM @CondTbl WHERE cID = @c) SET @ValType = (SELECT ValType FROM @CondTbl WHERE cID = @c) SET @VarTxt = (SELECT ValTxt FROM @CondTbl WHERE cID = @c) SET @VarNum = (SELECT ValValue FROM @CondTbl WHERE cID = @c) SET @SQL = 'SELECT * FROM @SearchTbl WHERE Var4 + CONVERT(VARCHAR(100), Time, 121) IN (SELECT Var4 + CONVERT(VARCHAR(100), Time, 121) AS TagTime FROM @SearchTbl' SET @SQL = @SQL + ' WHERE Var1 = @Var1 AND Var2 = @Var2' IF @ValType = 'Num' BEGIN SET @SQL = @SQL + ' AND VarNum ' + @CondSign + ' @VarNum' END IF @ValType = 'Text' BEGIN IF @CondSign = 'LIKE' BEGIN SET @SQL = @SQL + ' AND VarTxt LIKE @VarTxt' END IF @CondSign = 'NOT LIKE' BEGIN SET @SQL = @SQL + ' AND NOT VarTxt LIKE @VarTxt' END END SET @SQL = @SQL + ')' DELETE FROM @LoopTbl INSERT INTO @LoopTbl EXEC sp_executesql @SQL, N'@SearchTbl tempSearchTbl_tbltype READONLY, @Var1 nvarchar(255), @Var2 nvarchar(255), @Time datetime, @Var3 nvarchar(255), @UserName nvarchar(255), @VarNum float, @VarTxt nvarchar(4000), @CondSign nvarchar(30)', @SearchTbl, @Var1, @Var2, @Time, @Var3, @UserName, @VarNum, @VarTxt, @CondSign SET @c = @c + 1 DELETE FROM @SearchTbl INSERT INTO @SearchTbl SELECT * FROM @LoopTbl END END FinalReturn: SELECT DISTINCT eTime FROM @SearchTbl RETURN
Code to create the table types used in this procedure:
CREATE TYPE conditions_tbltype AS TABLE (cID int, Var1 nvarchar(255) NOT NULL, Var2 nvarchar(255) NOT NULL, condSign nvarchar(255) NOT NULL, ValType nvarchar(255), ValTxt nvarchar(4000) NOT NULL, ValValue float) CREATE TYPE tempSearchTbl_tbltype as TABLE (Var4 nvarchar(255), UserName nvarchar(255), Var3 nvarchar(255), Var1 nvarchar(255), VarNum float, VarTxt nvarchar(4000),NForm nvarchar(255), Var2 nvarchar(255), eTime datetime, Var4Var3Time nvarchar(255))