Sql-Server

UPDATE 觸發器導致死鎖

  • June 28, 2018

我有一個更新後觸發器,其中觸發器在同一個表中插入一個值以查找持續時間列。我的目標是每當插入 end_time 值時,觸發器將以hh:mm:ss格式查找持續時間並插入到持續時間列中。

問題 - 觸發器導致如此多的死鎖,因此阻塞了另一個程序。

列數據類型資訊

Start_time datetime, End_time datetime, Duration time(3)

ALTER TRIGGER [dbo].[GET_DURATION] ON [dbo].[INBOUND_CALL_xxx]
AFTER UPDATE AS
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Begin Transaction

              UPDATE INBOUND_CALL_xxx
              SET DURATION = convert(time(0),(END_TIME- START_TIME))                                                     
              FROM INBOUND_CALL_xxx with (nolock)
Commit;

您缺少對inserted僅包含已更新行的特殊表的引用。目前,您的觸發器每次都會更新跟踪表的所有行。

ALTER TRIGGER [dbo].[GET_DURATION] ON [dbo].[INBOUND_CALL_xxx]
AFTER UPDATE AS
BEGIN

   IF UPDATE(END_TIME) OR UPDATE(START_TIME)
   BEGIN

              UPDATE C
              SET DURATION = convert(time(0),(I.END_TIME - I.START_TIME))                                                     
              FROM 
               inserted AS I 
               INNER JOIN INBOUND_CALL_xxx AS C ON I.KeyColumn = C.KeyColumn

   END

END

您還可以修改觸發器以DURATION僅在更新相關列時才更新(如本範例所示)。


另一種選擇是使用帶有表達式的計算列(可能是持久化的)CONVERT(time(0), END_TIME - START_TIME),因此您不需要觸發器來保持值的更新。

ALTER TABLE INBOUND_CALL_xxx DROP COLUMN DURATION

ALTER TABLE INBOUND_CALL_xxx ADD DURATION AS CONVERT(TIME(0), END_TIME - START_TIME) -- PERSISTED (if needed)

每次有更新時,您似乎都在更新整個表。您應該參考 Inserted and Deleted 以僅更改實際更改的記錄的持續時間。我相信這是這裡的主要問題。

如果您在此觸發器中只有一個更新,則此處不需要開始事務/送出,因為 UPDATE 單獨是一個原子查詢,因此不能僅部分成功或失敗。

如果在解決此問題後,您仍然遇到死鎖,那麼您還可以查看更新此數據的其他程式碼和/或考慮將隔離級別更改為 READ COMMITTED SNAPSHOT ISOLATION。

引用自:https://dba.stackexchange.com/questions/210825