Quantcast
Channel: Transact-SQL forum
Viewing all articles
Browse latest Browse all 23857

Update Trigger and COLUMNS_UPDATED()

$
0
0

Let me rephrase my question:

I want to know if there is a faster way (probably using bit operators) to see if COLUMNS_UPDATED() in an update trigger on a table with more than 8 columns contains any column other than 1 specific column I will refer to as 'columnToIgnore'. I don't care about which columns are included or if the value has actually changed, only that there are other columns present.

Original question:

I have inherited a Sql Server database + schema and corresponding application and I have been tasked with speeding up the batch update of users in the database. After running some profiling I discovered that the reason it was slow is because of an update trigger on the users table. I did some “cleaning up” of the trigger and now it runs faster but I still think it could be more efficient. The objective of the trigger is to write to an Audit table any time an update takes place and any column is updated (it does not actually matter if the value has changed or not) with the exception of 1 specific column. Now I have the following code in the trigger which I had refactored from something much uglier.

DECLARE @ColumnsUpdated VARBINARY(100)
SET @ColumnsUpdated = COLUMNS_UPDATED()

DECLARE @onlyIgnoreColumnChanged int
SET @onlyIgnoreColumnChanged = 1

SET @onlyIgnoreColumnChanged = 1
IF (EXISTS(SELECT 1 
		FROM INFORMATION_SCHEMA.COLUMNS Field
		WHERE TABLE_NAME = 'users' 
		AND sys.fn_IsBitSetInBitmask(@ColumnsUpdated, COLUMNPROPERTY(OBJECT_ID('dbo.users'), COLUMN_NAME, 'ColumnID')) <> 0 
		AND column_name !='columnToIgnore')) BEGIN
	SET @onlyIgnoreColumnChanged = 0
END

Ideally I would change the code to disable the trigger and do the insert myself BUT the code is old Classic ASP ( ie. VBScript with ODBC database connections) so I am not going to change any of the calling code because that would cost too much time and probably create more problems than I am solving.

My proposed fix which I am unsure of how to code in SQL:

It seems to me that there should be a way to get the proper id or position for the column and see if the column was used in the COLUMNS_UPDATED().

  1. If it was not used then we can set @onlynieuwchanged to 0 for the remaining code (not shown)
  2. If it was used then remove the bit from the COLUMNS_UPDATED() and see if it is empty
    1. If its empty then then we can set @onlynieuwchanged to 1 for the remaining code (not shown)
    2. If it’s not empty then then we can set @onlynieuwchanged to 0 for the remaining code (not shown)

My problem is I am not sure how to go about coding this logic in SQL. I would think it would be possible with BIT operators? It would seem this could be more efficient than what I have now as it would get rid of the select statement which could slow down a large batch update.

Notes

  • My table has 30+ some columns so more than 8 which is relevant when working with COLUMNS_UPDATED() from what I have read. It also means that testing each column with UPDATE() would probably be more inefficient than what I have now.
  • The update is called from the front end code (VBScript) which currently times out although not as much as it used to with my latest change. I cannot alter the code to run async mode and show progress, it would be easier for me to update the trigger.
  • Reason for audit - we only record the user id in an audit table. This is then used to force a sync to another system outside of our source control that is used for various other tasks (mailings, views, etc). Again, I do not want to change how this system works, I only want to speed up the existing trigger with minimal effort.
  • Sql Server version 2012, database Schema is set to Sql server 2005 compatibility mode.

Any help would be greatly appreciated. Thank you in advance!

-Igor


Viewing all articles
Browse latest Browse all 23857

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>