如何防止此SQL发生死锁

问题描述 投票:0回答:2

首先,我不需要 100% 防止死锁,但我可以做任何事情来减少死锁。

我有两张桌子

Source
Dest
。源中包含大量唯一值,我需要从
Source
请求一个新值,并在此过程中将其移至
Dest

我有以下 SQL:

begin tran
    declare @value
    select top 1 @value = [value] from [source]
    delete from [Source] where [value]=@value
    insert into [Dest] ([Value]) values (@value)
    select @value
commit tran

当多个用户获取相同的

value
行时,这偶尔会引发死锁。我怎样才能预防/减少这种情况?

我使用的是 SQL Server 2008。

顺便说一句,我正在读取/写入

Source
Dest
中的其他列。这是为了简洁起见的简化。

t-sql database-deadlocks
2个回答
3
投票

您可以通过在 DELETE 命令中使用 OUTPUT 子句来避免这种竞争情况,因为它将从源中删除该值并在单个原子操作中返回它。我制作了以下脚本来演示这个概念:

-- dummy data
CREATE TABLE #source (mycolumn INT);
CREATE TABLE #destination (mycolumn INT);

INSERT #source VALUES (1);
INSERT #source VALUES (2);
INSERT #source VALUES (3);
GO

-- stored procedure to demonstrate concept
CREATE PROCEDURE move
AS BEGIN
    BEGIN TRANSACTION;

    DECLARE @tmp TABLE (mycolumn INT);
    DELETE TOP(1) #source OUTPUT DELETED.mycolumn INTO @tmp(mycolumn);

    INSERT #destination (mycolumn) OUTPUT INSERTED.mycolumn
    SELECT mycolumn
    FROM @tmp;

    COMMIT;
END
GO

-- testing
EXEC move;
GO -- remove from 1 from #source, insert 1 into #destination, returns 1

EXEC move;
GO -- remove from 2 from #source, insert 2 into #destination, returns 2

EXEC move;
GO -- remove from 3 from #source, insert 3 into #destination, returns 3

1
投票

您可以使用

XLOCK
语句来获取
SELECT

begin tran
    declare @value
    select top 1 @value = [value] from [source] with (XLOCK)
    delete from [Source] where [value]=@value
    insert into [Dest] ([Value]) values (@value)
    select @value
commit tran
© www.soinside.com 2019 - 2024. All rights reserved.