次のストアド プロシージャで断続的にデッドロックが発生します。1 分間に 1 回実行されます。1年以上運用されており、通常このエラーは発生しませんが、時々発生します...環境の1つで1日に3〜5回例外をスローしています...それは他のインスタンスと同じ環境ですエラーをスローしていません。ストアド プロシージャは、一度に 1 回しか実行できないように作成されていますが、この方法は適切ではないのでしょうか?
エラーは次のとおりです。
System.Web.HttpUnhandledException: タイプ 'System.Web.HttpUnhandledException' の例外がスローされました。---> System.Data.SqlClient.SqlException: トランザクション (プロセス ID 60) が別のプロセスのロック リソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行します。
ストアド プロシージャは次のとおりです。
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[requestUpdate]
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRAN
DECLARE @StartDate datetime,
@EndDate datetime,
@Throttle bit,
@Expired bit
SELECT @Throttle = 0
SELECT @Expired = 0
SELECT TOP 1 @StartDate = uq.StartDate, @EndDate = uq.EndDate
FROM UpdateQueue uq WITH(TABLOCK,XLOCK)
ORDER BY ID DESC
-- PREVENT ANOTHER REQUEST IF THIS SP HAS BEEN
-- CALLED IN THE LAST FORTY SECONDS.
IF DATEADD(SECOND,-40,GETDATE()) < @StartDate
BEGIN
SELECT @Throttle = 1
END
-- CREATE ANOTHER REQUEST IF THE CURRENT ONE
-- HAS NOT COMPLETED IN THE LAST FIVE MINUTES.
IF @StartDate <= DATEADD(MINUTE,-5,GETDATE())
BEGIN
SELECT @Expired = 1
END
-- HAS THE CURRENT REQUEST EXPIRED?
IF @EndDate IS NULL AND @Expired = 1
BEGIN
INSERT INTO UpdateQueue (RequestID, StartDate) OUTPUT 'EXPIRED' AS Result, INSERTED.RequestID AS RequestID
VALUES (NEWID(), GETDATE())
END
-- HAS THE CURRENT REQUEST COMPLETED AND YOU ARE NOT THROTTLING
-- OR HAVE THERE NOT BEEN ANY REQUESTS YET?
ELSE IF (@EndDate IS NOT NULL AND @Throttle = 0) OR @StartDate IS NULL
BEGIN
INSERT INTO UpdateQueue (RequestID, StartDate) OUTPUT 'STARTED' AS Result, INSERTED.RequestID AS RequestID
VALUES (NEWID(), GETDATE())
END
-- Running
ELSE
BEGIN
SELECT 'RUNNING' AS Result, NULL AS RequestID
END
COMMIT