Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
hiteshp27
Starting Member
3 Posts |
Posted - 2012-12-10 : 11:26:28
|
Hi,I have a question related to SPID used within a cursor in a trigger in SQL Server 2008 R2.I have a trigger for update on a table. This trigger is using cursor to iterate over the inserted rows. In the cursor there is a statement that calls a stored procedure that creates a global temp table using SPID if the one does not exists already.Now, since this entire thing is happening for each row in the cursor, I think it is affecting overall trigger performance. I was thinking to move the call to stored procedure out of the cursor. Here is the sample trigger code.create trigger POSUPD_TRNCHRGSon TRANSACTIONCHARGESfor updateas declare @trnCode nvarchar(30) declare @trnDesc nvarchar(50) declare @nReturn nvarchar(50) declare @sTransactionid nvarchar(30) if @@ROWCOUNT > 0 begin SET NOCOUNT ON -- MOVE HERE declare c_updated cursor local for select trn_code, trn_desc from inserted open c_inserted fetch next from c_inserted into @trnCode, @trnDesc while @@FETCH_STATUS = 0 begin -- This is the call that executes GETSESSIONVARIABLE for each row of the cursor -- The GETSESSIONVARIABLE stored procedure creates the global temp table based on SPID if the one does not exists -- I wanted to move this call out of the while loop at comment MOVE HERE EXECUTE @nReturn = GETSESSIONVARIABLE @sTransactionid OUTPUT if @@ERROR <> 0 or @nReturn <> 0 begin close c_updated deallocate c_updated rollback transaction return end -- Take necessary action here... end endGO I am not sure of one thing while moving the call to stored procedure GETSESSIONVARIABLE out of the cursor.Do we have a chance that for a single trigger execution we receive different SPIDs for each row iteration? Is there such chance if there are multiple updates from multiple users happening?Regards,Hitesh |
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2012-12-10 : 13:19:39
|
quote: Now, since this entire thing is happening for each row in the cursor, I think it is affecting overall trigger performance
That is the understatement of the week. I'm not clear on why you need a "global temp table based on SPID". What's wrong with a plain ol' temp table? Why would other spids need to access that data? What "session" data are you creating/storing in that stored procedure? (posting that code would help us troubleshoot better) |
|
|
Lamprey
Master Smack Fu Yak Hacker
4614 Posts |
Posted - 2012-12-10 : 13:56:31
|
Any chance that you can tell us what you are trying to do? We might be able to come up with a set-based solution which will, more than likely, be faster. Using a cursor, especially in a trigger, is probably not the best approach. |
|
|
hiteshp27
Starting Member
3 Posts |
Posted - 2012-12-11 : 17:22:40
|
Thanks robvolk and Lamprey for your replies.robvolk, I am not sure why the stored procedure is using global temp table, because that is the legacy stored procedure we have and I really do not want to touch it. I can however tell you that the purpose of creating that global temp table based on SPID is because it tries to achieve the concept similar to packages in oracle.Since the original stored procedure is big, I am pasting here only the required number of lines. The trigger code having call to this stored procedure is already given in my previous example.create procedure GETSESSIONVARIABLE @sPackage nvarchar(32), @sVariable nvarchar(32), @sValue nvarchar(2000) OUTPUTas SET NOCOUNT ON declare @sSQL nvarchar(500) declare @sTable nvarchar(32) declare @nCount int SET @sValue = N'@@Error@@' SET @sTable = N'##GTMP_PACKAGE_VARIABLES' + CAST( @@SPID as nvarchar(10) ) --create temp table if table does not already exist if object_id('tempdb..' + @sTable ) is null BEGIN SET @sSQL = N'select * into ' + @sTable + N' from PACKAGEVARIABLES' EXEC (@sSQL) END --verify its existance if object_id('tempdb..' + @sTable ) is null RAISERROR ('Unable to create temporary package variable table.', 16, 1 ) --get the package variable value SET @sSQL = N'select @sValue = VARIABLE_VALUE from ' + @sTable SET @sSQL = @sSQL + N' where PACKAGE_NAME = ''' + @sPackage + N''' and ' SET @sSQL = @sSQL + N' VARIABLE_NAME = ''' + @sVariable + N'''' EXEC sp_executesql @sSQL, N'@sValue nvarchar(2000) OUTPUT', @sValue OUTPUTgo The stored procedure above may not compile as a whole, but should be sufficient to give you better idea.Since this stored procedure is called from a trigger within cursor, I was looking to move it out for performance reason. My question is, if I move the call to GETSESSIONVARIABLE out of the cursor, do we have chance to break the original purpose of calling the stored proc within cursor? I am mainly confused because it is using SPID. I personally do not see that the value of SPID would differ for single trigger execution, but I wanted to confirm it with advanced users. |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2012-12-11 : 17:51:31
|
That makes sense, this was almost certainly generated by the SQL Server Migration Wizard Assistant. I wouldn't recommend changing it either, even though it sucks. Rewriting this would require looking at the packages involved and seeing how/if the package variables are modified, and unless you have a very small migrated codebase is probably not worthwhile.From what I can tell in this code though, the dumbass Microsoft programmer that wrote this could have used a single table for ##GTMP_PACKAGE_VARIABLES and included a SPID column to managed each SPID's values from PACKAGEVARIABLES, and adding a WHERE condition for SPID=@@SPID. That would have eliminated the need for dynamic SQL and multiple global temp tables. That's the only avenue I'd recommend re: rewriting this code, you'd also have to look for and modify a SETSESSIONVARIABLE procedure to match.One thing I should point out, the trigger defines @sTransactionid as nvarchar(30), but the GETSESSIONVARIABLE @sValue output parameter is declared nvarchar(2000). This could cause data truncation. |
|
|
hiteshp27
Starting Member
3 Posts |
Posted - 2012-12-13 : 12:03:33
|
Thanks robvolk for ruling out the option of rewriting the code to avoid multiple global temp tables.My original question still remains unanswered though. Can I at least for performance reason move the call to GETSESSIONVARIABLE out of the while loop of a cursor in trigger? Do you see any issue here if I move the call out at MOVE HERE comment? That way I can at least save myself from calling GETSESSIONVARIABLE multiple times. |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2012-12-13 : 12:33:28
|
I can't answer that without seeing what the trigger actually does. The code you posted doesn't even reference the cursor, and the call to GETSESSIONVARIABLE doesn't look complete either, it's not passing the package or variable names, it should throw an error in that state. |
|
|
|
|
|
|
|