我正在学习更复杂的SQL Server 2008技术,所以如果我问太明显的问题,我会提前道歉。t-SQL复合语句导致死锁,任何想法为什么?
我有这样创建如下表:
CREATE TABLE [dbo].[t_Log_2]
(
[id] INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
[oid] INT,
[idtm] DATETIME2,
[odtm] DATETIME2,
[type] TINYINT,
[state] TINYINT,
[huid] UNIQUEIDENTIFIER,
[cnm] NVARCHAR(256),
[cmdl] NVARCHAR(256),
[batt] TINYINT,
[dvtp0] SMALLINT,
[dvtp1] SMALLINT
);
CREATE INDEX idx_idt
ON [dbo].[t_Log_2]([idtm]);
CREATE INDEX idx_odt
ON [dbo].[t_Log_2]([odtm]);
CREATE INDEX idx_huid
ON [dbo].[t_Log_2]([huid]);
CREATE INDEX idx_cnm
ON [dbo].[t_Log_2]([cnm]);
然后将下面的查询可以从几个并发线程从ASP.NET Web应用程序运行。请注意,此整个查询需要运行原子:
SET XACT_ABORT ON;
BEGIN TRANSACTION;
DELETE FROM [dbo].[t_Log_2]
WHERE [idtm]<'2011-03-12 08:41:57';
WITH ctx AS(
SELECT MIN([idtm]) AS mdIn,
MAX([odtm]) AS mdOut
FROM [dbo].[t_Log_2]
WHERE [type] = 0
AND [state] = 0
AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'
AND [odtm] >= '2013-03-11 06:33:32'
AND [idtm] <= '2013-03-11 06:43:12'
)
INSERT INTO [dbo].[t_Log_2]
([oid],[idtm],[odtm],[type],[state],[huid],
[cnm],[cmdl],[batt],[dvtp0],[dvtp1])
SELECT
2,
CASE WHEN mdIn IS NOT NULL
AND mdIn < '2013-03-11 06:33:32'
THEN mdIn
ELSE '2013-03-11 06:33:32'
END,
CASE WHEN mdOut IS NOT NULL
AND mdOut > '2013-03-11 06:43:12'
THEN mdOut
ELSE '2013-03-11 06:43:12'
END,
0,
0,
N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4',
null,
null,
0,
1,
null
FROM ctx
SELECT ROWCOUNT_BIG()
DELETE FROM [dbo].[t_Log_2]
WHERE [type] = 0
AND [state] = 0
AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'
AND [odtm] >= '2013-03-11 06:33:32'
AND [idtm] <= '2013-03-11 06:43:12'
AND [id] <> SCOPE_IDENTITY()
DELETE FROM [dbo].[t_Log_2]
WHERE [type] = 0
AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'
AND [idtm] >= (SELECT [idtm] FROM [dbo].[t_Log_2]
WHERE [id] = SCOPE_IDENTITY())
AND [odtm] <= (SELECT [odtm] FROM [dbo].[t_Log_2]
WHERE [id] = SCOPE_IDENTITY())
AND [id] <> SCOPE_IDENTITY()
;WITH ctx1 AS(
SELECT [idtm] AS dI
FROM [dbo].[t_Log_2]
WHERE [id] = SCOPE_IDENTITY()
)
UPDATE [dbo].[t_Log_2]
SET [odtm] = ctx1.dI
FROM ctx1
WHERE [id] <> SCOPE_IDENTITY()
AND [type] = 0
AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'
AND [idtm] < ctx1.dI
AND [odtm] > ctx1.dI
;WITH ctx2 AS(
SELECT [odtm] AS dO
FROM [dbo].[t_Log_2]
WHERE [id] = SCOPE_IDENTITY()
)
UPDATE [dbo].[t_Log_2]
SET [idtm] = ctx2.dO
FROM ctx2
WHERE [id] <> SCOPE_IDENTITY()
AND [type] = 0
AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'
AND [idtm] < ctx2.dO
AND [odtm] > ctx2.dO
COMMIT TRANSACTION;
SET XACT_ABORT OFF
注意,上面的查询被复制1对1的从动态构成它的C#代码。实际上,它的参数并非如上所示的硬编码。
该查询工作在大部分时间,但一旦我得到的日志中出现以下错误一阵:
事务(进程ID 80)已被死锁的锁资源与 另一个进程,并已被选作死锁受害者。重新运行 交易。
任何想法我该怎么做才能防止这种僵局?
在您的选择上使用UPDLOCK提示。 – Arvo 2013-03-12 09:21:41
捕获并附加死锁图形(XML,不是它的图片!)请参见[保存死锁图形(SQL Server Profiler)](http://msdn.microsoft.com/zh-cn/library/ms190465.aspx) – 2013-03-12 09:28:44
@Arvo:你能解释一下多一点吗? – c00000fd 2013-03-12 09:29:20