2013-03-12 37 views
1

我正在學習更復雜的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)已被死鎖的鎖資源與 另一個進程,並已被選作死鎖受害者。重新運行 交易。

任何想法我該怎麼做才能防止這種僵局?

+1

在您的選擇上使用UPDLOCK提示。 – Arvo 2013-03-12 09:21:41

+5

捕獲並附加死鎖圖形(XML,不是它的圖片!)請參見[保存死鎖圖形(SQL Server Profiler)](http://msdn.microsoft.com/zh-cn/library/ms190465.aspx) – 2013-03-12 09:28:44

+0

@Arvo:你能解釋一下多一點嗎? – c00000fd 2013-03-12 09:29:20

回答

0

您或者需要持有更多的鎖或更少的鎖。

最簡單的答案是去NOLOCK(最佳性能)或TABLOCKX(一致性不用考慮)。

如果因爲一致性要求不能使用with (nolock),可以添加with (tablockx)。 這實際上意味着一次只有一個線程可以執行類似語句 - 不會有併發性。

另一種方法是分析你的要求有更詳細的,不能沒有理解爲什麼要更新的表來完成,哪些數據是等

例如,做這種說法真的需要在交易中?它聞起來像管家:

DELETE FROM [dbo].[t_Log_2] 
    WHERE [idtm]<'2011-03-12 08:41:57'; 

如果您採取了上述交易,並把它放在一個單獨的批處理,您可能會發現問題消失。

+1

很少是答案。只需使用READ COMMITTED,它不會保持鎖定,只需要釋放它們。不會以主要方式促成僵局。 – usr 2013-03-12 11:00:58

相關問題