August 25, 2004 at 8:44 am
I have an update trigger that, when enabled on the table, causes an update query to never finish (I've let it run as much as 24 minutes). If a single record is being updated it works fine. When I do a mass update, every record from another table matching a foreign key here (about 11,500), I have the problem. If I disable the trigger the update works fine, but I don't get the intended results in the table.
Background: I must extract a bunch of information from HR to put into AP so that AP can send out expense checks to employees. I extract the necessary data from several different fields in HR and put that data into a single table set up for this purpose. The Update trigger is supposed to look at the values being updated for certain fields, and if the value is different from the previous value, update that field, put the old value in another field, and update the LastUpdated date field. The fields involved are name or address fields that may change.
Trigger contents:
CREATE TRIGGER trgUpdateVendorList ON [dbo].[laPSVendorExport]
Instead of UPDATE
AS
--In a case where this is an update, we must check to see if certain fields are updated and flag them when necessary.
--Name changes must be flagged (insert current date into the NameChanged field).
If Update(FirstName)
Update PS
Set OldFirstName = D.FirstName,
FirstName = I.FirstName,
NameChanged = GetDate()
From Deleted D, Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
And I.FirstName <> D.FirstName
If Update(LastName)
Update PS
Set OldLastName = D.LastName,
LastName = I.LastName,
NameChanged = GetDate()
From Deleted D, Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
And I.LastName <> D.LastName
If Update(MiddleName)
Update PS
Set OldMiddleName = D.MiddleName,
MiddleName = I.MiddleName,
NameChanged = GetDate()
From Deleted D, Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
And I.MiddleName <> D.MiddleName
--Address changes must be flagged (insert current date into the AddressChanged field).
If Update(Street1)
Update PS
Set OldStreet1 = D.Street1,
Street1 = I.Street1,
AddressChanged = GetDate()
From Deleted D, Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
And I.Street1 <> D.Street1
If Update(Street2)
Update PS
Set OldStreet2 = D.Street2,
Street2 = I.Street2,
AddressChanged = GetDate()
From Deleted D, Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
And I.Street2 <> D.Street2
If Update(City)
Update PS
Set OldCity = D.City,
City = I.City,
AddressChanged = GetDate()
From Deleted D, Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
And I.City <> D.City
If Update(State)
Update PS
Set OldState = D.State,
State = I.State,
AddressChanged = GetDate()
From Deleted D, Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
And I.State <> D.State
If Update(Zip)
Update PS
Set OldZip = D.Zip,
Zip = I.Zip,
AddressChanged = GetDate()
From Deleted D, Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
And I.Zip <> D.Zip
--Just update these fields inf an update comes through, no tracking needed.
If Update(Prefix)
Update PS
Set PreFix = I.Prefix
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(Suffix)
Update PS
Set Suffix = I.Suffix
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(Email)
Update PS
Set Email = I.Email
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(DateHired)
Update PS
Set DateHired = I.DateHired
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(TermDate)
Update PS
Set TermDate = I.TermDate
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(UnitNumber)
Update PS
Set UnitNumber = I.UnitNumber
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(SupervisorFirst)
Update PS
Set SupervisorFirst = I.SupervisorFirst
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(SupervisorLast)
Update PS
Set SupervisorLast = I.SupervisorLast
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(SupervisorEmpNum)
Update PS
Set SupervisorEmpNum = I.SupervisorEmpNum
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(NetworkAccount)
Update PS
Set NetworkAccount = I.NetworkAccount
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(NameChanged)
Update PS
Set NameChanged = I.NameChanged
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(AddressChanged)
Update PS
Set AddressChanged = I.AddressChanged
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
The Update query (where clause omitted)
Update PS
Set
PS.FirstName = EB.ebFirstName,
PS.LastName = EB.ebLastName,
PS.MiddleName = EB.ebMiddleName,
PS.EmpNumber = EB.ebClock,
PS.Prefix = EP.epPrefix,
PS.Suffix = EP.epSuffix,
PS.Email = EP.epEmail,
PS.Street1 = EP.epStreet1,
PS.Street2 = EP.epStreet2,
PS.City = EP.epCity,
PS.State = EP.epState,
PS.Zip = EP.epZip,
PS.DateHired = RTrim(IsNull(Convert(Char(10),EE.eeDateLastHire, 110), Space(10))),
PS.TermDate = RTrim(IsNull(Convert(Char(10), EE.eeTermDate, 110), Space(10))),
PS.UnitNumber = EJ.ejDivision,
PS.SupervisorFirst = IsNull(EB1.ebFirstName, ''),
PS.SupervisorLast = IsNull(EB1.ebLastName, ''),
PS.SupervisorEmpNum = IsNull(EB1.ebClock, ''),
PS.NetworkAccount = IsNull(D.Network_Account, '')
From Ebase EB
Inner Join ePerson EP On EB.ebFlxID = EP.epFlxIDeb
Inner Join eEmploy EE On EB.ebFlxID = EE.eeFlxIDeb
Inner Join eJob EJ On EB.ebFlxID = EJ.ejFlxIDeb
Left Join eBase EB1 On EJ.ejSupervisorFlxIDeb = EB1.ebFlxID
Left Join svariINDB03.Directory_New.dbo.Person D On EB.ebClock = D.Employee_Num
Inner Join laPSVendorExport PS On EB.ebClock = PS.EmpNumber
Any suggestions on why this will not let a "mass" update work will be appreciated.
Thanks,
Chris
August 26, 2004 at 6:43 am
I can think of 2 things, 1st you could try updating 100 rows at time to see if the update trigger actually works and if the time required is lower. And 2nd this query can be optimized a lot :
If Update(Prefix)
Update PS
Set PreFix = I.Prefix
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(Suffix)
Update PS
Set Suffix = I.Suffix
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(Email)
Update PS
Set Email = I.Email
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(DateHired)
Update PS
Set DateHired = I.DateHired
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(TermDate)
Update PS
Set TermDate = I.TermDate
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(UnitNumber)
Update PS
Set UnitNumber = I.UnitNumber
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(SupervisorFirst)
Update PS
Set SupervisorFirst = I.SupervisorFirst
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(SupervisorLast)
Update PS
Set SupervisorLast = I.SupervisorLast
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(SupervisorEmpNum)
Update PS
Set SupervisorEmpNum = I.SupervisorEmpNum
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(NetworkAccount)
Update PS
Set NetworkAccount = I.NetworkAccount
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(NameChanged)
Update PS
Set NameChanged = I.NameChanged
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
If Update(AddressChanged)
Update PS
Set AddressChanged = I.AddressChanged
From Inserted I, laPSVendorExport PS
Where PS.EmpNumber = I.EmpNumber
skip the if update() and do 1 statement that checks it all at once like :
Update PS set AddressChanged = I.AdressChanded, Col1 = I.Col1, (Update all fields) from Inserted I inner join laPSVendorExport PS on I.EmpNumber = PS.EmpNumber where (Col1 I.Col1 or Col2 I.Col2 ....)
this will be much faster because you will do the inner join only once and the update checks will be minimal.
August 26, 2004 at 12:42 pm
Thanks for the reply. I used some of your suggestions and did some calculations to find that I wasn't waiting long enough for the query to complete, by about 15 minutes. I made some adjustments to the update query against that table, to only update stuff that is different, and it runs much faster now. Below is the final of the trigger, which works great if you don't try to feed it 11,500 records at one sitting.
Thanks,
Chris
CREATE TRIGGER trgAddOrUpdateVendorList ON dbo.laPSVendorExport
Instead of Insert, Update
As
--Do not insert data for Employee Number that already exists
If (Not Exists(Select PS.EmpNumber From laPSVendorExport PS
Inner Join Inserted I On PS.EmpNumber = I.EmpNumber ))
Begin
Insert Into laPSVendorExport
(FirstName, LastName, MiddleName, EmpNumber, Prefix, Suffix, Email,
Street1, Street2, City, State, Zip, DateHired, TermDate, UnitNumber,
SupervisorFirst, SupervisorLast, SupervisorEmpNum, NetworkAccount)
Select
FirstName, LastName, MiddleName, EmpNumber, Prefix, Suffix, Email,
Street1, Street2, City, State, Zip, DateHired, TermDate, UnitNumber,
SupervisorFirst, SupervisorLast, SupervisorEmpNum, NetworkAccount
From Inserted
End
Else --In a case where this is an update, we must check to see if certain fields are updated and flag them when necessary.
--Name changes must be flagged (insert current date into the NameChanged field).
Update PS
Set OldFirstName = D.FirstName,
FirstName = I.FirstName,
NameChanged = GetDate()
From Deleted D Inner Join Inserted I On D.EmpNumber = I.EmpNumber
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.FirstName <> D.FirstName
Update PS
Set OldLastName = D.LastName,
LastName = I.LastName,
NameChanged = GetDate()
From Deleted D Inner Join Inserted I On D.EmpNumber = I.EmpNumber
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.LastName <> D.LastName
Update PS
Set OldMiddleName = D.MiddleName,
MiddleName = I.MiddleName,
NameChanged = GetDate()
From Deleted D Inner Join Inserted I On D.EmpNumber = I.EmpNumber
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.MiddleName <> D.MiddleName
--Address changes must be flagged (insert current date into the AddressChanged field).
Update PS
Set OldStreet1 = D.Street1,
Street1 = I.Street1,
AddressChanged = GetDate()
From Deleted D Inner Join Inserted I On D.EmpNumber = I.EmpNumber
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.Street1 <> D.Street1
Update PS
Set OldStreet2 = D.Street2,
Street2 = I.Street2,
AddressChanged = GetDate()
From Deleted D Inner Join Inserted I On D.EmpNumber = I.EmpNumber
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.Street2 <> D.Street2
Update PS
Set OldCity = D.City,
City = I.City,
AddressChanged = GetDate()
From Deleted D Inner Join Inserted I On D.EmpNumber = I.EmpNumber
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.City <> D.City
Update PS
Set OldState = D.State,
State = I.State,
AddressChanged = GetDate()
From Deleted D Inner Join Inserted I On D.EmpNumber = I.EmpNumber
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.State <> D.State
Update PS
Set OldZip = D.Zip,
Zip = I.Zip,
AddressChanged = GetDate()
From Deleted D Inner Join Inserted I On D.EmpNumber = I.EmpNumber
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.Zip <> D.Zip
--Just update these fields if an update comes through, no tracking needed.
Update PS
Set
PS.PreFix = I.Prefix,
PS.Suffix = I.Suffix,
PS.Email = I.Email,
DateHired = I.DateHired,
TermDate = I.TermDate,
UnitNumber = I.UnitNumber,
SupervisorFirst = I.SupervisorFirst,
SupervisorLast = I.SupervisorLast,
SupervisorEmpNum = I.SupervisorEmpNum,
NetworkAccount = I.NetworkAccount
From Inserted I
Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
August 26, 2004 at 2:39 pm
I think you could make it even faster... I noticed that you are joining deleted to inserted on every update query. What you are doing is asking sql server to join to tables of 11500 lines 9 times in a row. You could avoid this using a table variable (create table variable, insert the joined inserted and deleted tables, then join on the Table variable).
but even faster than that.. couldn't you just do this instead :
Update PS
Set OldFirstName = D.FirstName,
FirstName = I.FirstName,
NameChanged = GetDate()
From Inserted I Inner Join laPSVendorExport PS On PS.EmpNumber = I.EmpNumber
Where I.FirstName PS.FirstName
Since you want to update only the lines that are updated, you can check in the original table against the inserted table to see if anything has changed (which makes about 100 000 less lines to join to 🙂 )
if that table gets a lot of hits you may notice a difference even in production evironnement (not only with 11500 records)
August 26, 2004 at 2:44 pm
BTW I would be interested to know what's the final speed compared to the original trigger you posted... I curious to know how much of a difference that makes (the tests I made gave from 4 to 10 times faster depending on the queries).
August 27, 2004 at 6:59 am
Remi,
What you suggested about is actually what I am doing now. I join my update query to the destination table and then compare the source and destination fields for inequality before I update them. I am trying to work out some trash data problems now, but it returns 2 records in the update in about 13 seconds. This should run faster, but I cannot test it until I work out this trash data. The 2 records it returns are for the same user, and look identical, meaning one of my joined tables has bad data.
Thanks,
Chris
Viewing 6 posts - 1 through 5 (of 5 total)
You must be logged in to reply to this topic. Login to reply