首先,我不需要 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
中的其他列。这是为了简洁起见的简化。
您可以通过在 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
您可以使用
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