使用 SQL 服务器插入/更新死锁

Insert / update Deadlock with SQL Server

我有一个 table A (id int, domain nvarchar, status nvarchar) 和一个触发器 A_trigger after insert on table A.触发器调用一个存储过程和根据过程的结果,更新新插入行的状态。

当我在两个会话中 运行 时,我遇到了死锁问题:

隔离级别:读提交

INSERT 语句:

INSERT INTO dbo.TEST_TRIGGER (DOMAIN) 
VALUES ('toto')

触发器:

CREATE TRIGGER dbo.dim_trigger 
ON db.dbo.TEST_TRIGGER
AFTER INSERT
AS
    DECLARE @status nvarchar(200),
            @domain nvarchar(200),
            @trackingId int

BEGIN
    SET NOCOUNT ON;

    -- This code assumes we insert one and only one row at a time.
    SELECT @trackingId = id, @domain = domain FROM INSERTED;

    DECLARE @toCallProcName NVARCHAR(200);
    SET @toCallProcName = 'db.dbo.'+@domain+'_proc';

    EXEC @toCallProcName @status out;

    UPDATE db.dbo.TEST_TRIGGER
    SET status = @status
    WHERE id = @trackingId;
END

我试过:

EDIT1:

Table 架构:

CREATE TABLE [dbo].[TEST_TRIGGER]
(
      [DOMAIN] [NVARCHAR](200) NOT NULL,
      [ID] [BIGINT] IDENTITY(1,1) NOT NULL,
      [STATUS] [NVARCHAR](100) NULL
)

存储过程:

CREATE PROCEDURE [dbo].[toto_proc]
     @res NVARCHAR(200) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    WAITFOR DELAY '00:00:5'
    PRINT 'This is me: '+CONVERT(VARCHAR(8), GETDATE(), 108) ;
    SET @res = 'OK'
END

有什么帮助吗?

谢谢

您需要做的是在 table

上创建一个索引

示例:

CREATE INDEX IX_Test_Trigger ON dbo.TEST_TRIGGER(Id)

阅读此内容以了解有关索引及其对锁定机制的影响的更多信息: https://www.mssqltips.com/sqlservertip/2517/using-a-clustered-index-to-solve-a-sql-server-deadlock-issue/

您的问题的原因是,触发器一直保持对基座的锁定 table。由于多个会话和相同的资源,这必然会发生。在 table 上没有索引将导致每次对每个不同的会话进行 table 扫描并导致死锁。应用索引是正确的做法,因为这样你的更新语句就会达到粒度级别。所以这应该有效。我建议在您的更新语句中添加额外的 RowLock 提示。

重要提示:我假设,每个插入将只插入一个值。否则这个触发器有问题。 (如marc_s所述)