Reputation: 1564
I have an SQL table called Agent_Events, which logs "jobs" for lack of a better term reported by users of our system. Jobs will start and, some indetermine time later, end. We want to keep a record of all system jobs so we have a trigger that, when a row is deleted from the Agent_Events table, gets the record, and inserted into the report_Agent_Events table a record of the job with the time the job ended, determined by the current time. This is the trigger:
ALTER TRIGGER [dbo].[tAgentEvents]
ON [dbo].[Agent_Events]
AFTER DELETE
AS
BEGIN
SET NOCOUNT ON
DECLARE @callUID nvarchar(10)
SELECT @callUID = [raw_call_ucid] FROM DELETED
DECLARE @callID bigint
SELECT TOP 1 @callID = [ID] FROM report_ExtensionCalls WHERE UCID = @callUID ORDER BY [time_finished] DESC
INSERT INTO [report_agent_Events]
([Agent_Name],[time_started],[time_ended],[duration],[clientStatus],[agentStatus],[Call_ID],[Reference_ID])
( SELECT
[Agent_Name],[time_started],GETDATE(),DATEDIFF(s,[time_started],GETDATE()),[clientStatus],[agentStatus],@callID as Call_ID,[Reference_ID]
FROM
DELETED
)
END
What we have discovered recently is that when there is a high volume of activity on the system, multiple jobs could end simultaneously. When this happens, the trigger will fail with the following deadlock error:
Procedure tAgentEvents:
Transaction (Process ID) was deadlocked on lock resources with another process and has been chosen as the deadlock victim RSS
It looks like the INSERT statement in the trigger is conflicting with the lock imposed by the same INSERT statement in a concurrent trigger. Is there anything I can do to avoid this problem? This appears to me like a very simple trigger.
Thanks in advance.
Upvotes: 1
Views: 953
Reputation: 331
Just updated the trigger to make it work in one go, with multiple lines deleted and with multiple matches in report_ExtensionCalls.
ALTER TRIGGER [dbo].[tAgentEvents]
ON [dbo].[Agent_Events]
AFTER DELETE
AS
BEGIN
WITH CTE AS (
SELECT d.Id AS DeletedId
, rec.[ID]
, ROW_NUMBER() OVER (PARTITION BY rec.UCID ORDER BY rec.[time_finished] DESC) AS RowN
FROM DELETED AS d
JOIN report_ExtensionCalls AS rec ON d.[raw_call_ucid] = rec.UCID
)
INSERT INTO [report_agent_Events]
([Agent_Name],[time_started],[time_ended],[duration],[clientStatus],[agentStatus],[Call_ID],[Reference_ID])
( SELECT
d.[Agent_Name]
,d.[time_started]
,GETDATE()
,DATEDIFF(s,d.[time_started],GETDATE())
,d.[clientStatus]
,d.[agentStatus]
,a.[ID] as Call_ID
,d.[Reference_ID]
FROM DELETED AS d
LEFT JOIN CTE AS a ON d.Id = a.DeletedId AND a.RowN = 1
)
END
Hope it helps
Upvotes: 0
Reputation: 33581
This should accommodate all the business rules in your original trigger but without scalar variables.
Please note, this is incredibly unlikely to solve the deadlock issue. You still need to sort that out.
INSERT INTO [report_agent_Events]
(
[Agent_Name]
, [time_started]
, [time_ended]
, [duration]
, [clientStatus]
, [agentStatus]
, [Call_ID]
, [Reference_ID]
)
SELECT [Agent_Name]
, [time_started]
, GETDATE()
, DATEDIFF(SECOND, [time_started], GETDATE())
, [clientStatus]
, [agentStatus]
, raw_call_ucid
, [Reference_ID]
FROM DELETED d
join
(
select top 1 ID as CallID
from report_ExtensionCalls ec
where ec.UCID = d.raw_call_ucid
order by [time_finished] DESC
) e on e.CallID = d.raw_call_ucid
Upvotes: 1