我在尝试锁定某些记录时遇到了死锁问题,因此没有进程(Windows服务)选择要为其提供服务的项目,然后更新状态然后返回记录集。
请你告诉我为什么在调用此proc时遇到死锁问题?
CREATE PROCEDURE [dbo].[sp_LoadEventsTemp]
(
@RequestKey varchar(20),
@RequestType varchar(20),
@Status varchar(20),
@ScheduledDate smalldatetime = null
)
AS
BEGIN
declare @LoadEvents table
(
id int
)
BEGIN TRANSACTION
if (@scheduledDate is null)
Begin
insert into @LoadEvents (id)
(
Select eventqueueid FROM eventqueue
WITH (HOLDLOCK, ROWLOCK)
WHERE requestkey = @RequestKey
and requesttype = @RequestType
and [status] = @Status
)
END
else
BEGIN
insert into @LoadEvents (id)
(
Select eventqueueid FROM eventqueue
WITH (HOLDLOCK, ROWLOCK)
WHERE requestkey = @RequestKey
and requesttype = @RequestType
and [status] = @Status
and (convert(smalldatetime,scheduleddate) <= @ScheduledDate)
)
END
update eventqueue set [status] = 'InProgress'
where eventqueueid in (select id from @LoadEvents)
IF @@Error 0
BEGIN
ROLLBACK TRANSACTION
END
ELSE
BEGIN
COMMIT TRANSACTION
select * from eventqueue
where eventqueueid in (select id from @LoadEvents)
END
END
提前致谢。
答案 0 :(得分:1)
您是否将非聚集索引定义为:
CREATE NONCLUSTERED INDEX NC_eventqueue_requestkey_requesttype_status
ON eventqueue(requestkey, requesttype, status)
INCLUDE eventqueueid
和另一个关于eventqueueid?
BTW将列scheduleddate
转换为smalldatetime
类型将阻止在该列上使用任何索引。
答案 1 :(得分:1)
首先,当您运行SQL Server时,我建议您安装Performance Dashboard,这是一个非常方便的工具,用于识别当前在服务器上进行的锁定。
其次,使用SQL事件探查器(已安装)跟踪您的SQL Server,并确保在事件选择上选择项目锁定&gt;死锁图将显示导致死锁的原因。
你必须清楚地知道什么是死锁才能开始排除故障。 当对DB上的任何表或行进行任何访问时,都会进行锁定。
允许调用SPID 51和SPID 52(SPID = SQL进程ID)
SPID 51锁定Cell A
SPID 52锁定Cell B
如果在同一事务SPID 51请求Cell B,它将等待SPID 52直到它释放它。
如果在同一事务SPID 52请求单元A,则会出现死锁,因为这种情况永远不会完成(51等待52和52为51)
告诉你要排除故障并不容易,但你要深入挖掘才能找到解决方案
答案 2 :(得分:0)
当不同的资源被锁定在不同订单的不同交易中时,死锁最常发生(根据我的经验)。
想象一下使用资源A和B的2个进程,但是以不同的顺序锁定它们
- 进程1锁定资源A,然后锁定资源B
- 进程2锁定资源B,然后锁定资源A
以下可能成为可能:
- 进程1锁定资源A
- 进程2锁定资源B
- 进程1尝试锁定资源B,然后停止并等待进程2拥有它
- 进程2尝试锁定资源A,然后停止并等待进程1拥有它
- 两个程序都在等待,死锁
在你的情况下,由于死锁(我猜的更新?)以及引用该表的任何其他进程,我们需要确切地看到SP落在哪里。它可能是一个触发器或其他东西,然后在另一个表上而不是你正在更新的表上陷入僵局。
我要做的是使用SQL Server 2005's OUTPUT syntaxt来避免使用交易......
UPDATE
eventqueue
SET
status = 'InProgress'
WHERE
requestkey = @RequestKey
AND requesttype = @RequestType
AND status = @Status
AND (convert(smalldatetime,scheduleddate) <= @ScheduledDate OR @ScheduledDate IS NULL)
OUTPUT
inserted.*