2015-11-25 51 views
1

我有一個名爲Agent_Events的SQL表,它記錄了「作業」,缺少我們的系統用戶報告的更好的術語。工作將開始,稍後的某個確定時間結束。我們想保留所有系統作業的記錄,所以我們有一個觸發器,當從Agent_Events表中刪除一行時,獲取該記錄並將其插入到report_Agent_Events表中,該作業的記錄隨着作業結束時間而確定到目前爲止。這是觸發器:執行插入導致死鎖的T-SQL觸發器

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 

我們最近發現的是,當系統上有大量活動時,多個作業可能會同時結束。發生這種情況時,觸發將失敗,並以下死鎖錯誤:

Procedure tAgentEvents: 
Transaction (Process ID) was deadlocked on lock resources with another process and has been chosen as the deadlock victim RSS 

它看起來像在觸發器的INSERT語句與同一INSERT語句在並行觸發規定的鎖衝突。有什麼我可以做,以避免這個問題?這在我看來就像一個非常簡單的觸發器。

在此先感謝。

+2

無論死鎖如何,您的觸發器都需要完全重寫。你的觸發器假定只有一行被刪除。您的查詢需要基於設置,因爲在sql服務器觸發器每個操作調用一次,而不是每行一次。 –

+0

啊好吧,我相信它是這樣寫的,因爲實際上行被存儲過程刪除,這確保只有一行被一次刪除。這仍然會有問題嗎? – Raiden616

+2

是的。出現問題時會發生什麼情況,並且由於系統中的錯誤,有人需要刪除10行。你的觸發器無法正常工作。很容易寫出它們基於集合。在這種情況下,將1列標記爲已刪除的標量確實沒有意義,但其餘標記直接來自已刪除的表。這應該是你的基表,刪除和report_ExtensionCalls –

回答

0

剛剛更新了觸發器,使其一次性工作,刪除了多行並在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 

希望它可以幫助

+0

是的,運行得更好 - 請參閱我對該問題的評論。謝謝您的幫助! – Raiden616

+0

是的 - 只是更新它考慮到,如果有更多的一個匹配report_ExtensionCalls –

+0

應該提及 - 不會總是有[raw_call_ucid]值..它有時會作爲NULL傳遞。只是改變首先加入到左連接應該修復,對吧? – Raiden616

1

這應該適應原來的觸發器,但沒有標變量的所有業務規則。

請注意,這非常不可能解決死鎖問題。你仍然需要整理出來。

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