2011-12-05 68 views
10

我們遇到了一些死鎖問題,我發佈了這個questionSQL Server,插入一行鎖整個表

隨着一些幫助和大量的搜索我自己,我相信我知道發生了什麼事情。爲了在不控制鎖升級的情況下解決死鎖問題,我需要了解爲什麼sql server在插入一行時鎖定整個表。

這裏是我的insert語句(用重命名的變量):

DECLARE 
    @Type1 INT = 11, 
    @Type2 INT = NULL, 
    @Value1 VARCHAR(20) = '0', 
    @Value2 VARCHAR(20) = '0', 
    @Value3 VARCHAR(20) = '0', 
    @Value4 VARCHAR(20) = '0', 
    @Date1 DATETIME = '2011-11-25', 
    @Date2 DATETIME = '2011-11-25', 
    @Value5 NVARCHAR(50) = '', 
    @Value6 NVARCHAR(50) = '', 
    @Type3 INT = NULL, 
    @Value7 VARCHAR(20) = '4', 
    @Type4 INT = 4, 
    @Type5 INT = 15153, 
    @Type6 INT = 3, 
    @Type7 INT = 31, 
    @Type8 INT = 5976, 
    @Type9 INT = 5044, 
    @Guid1 UNIQUEIDENTIFIER = 'a8293471-3hb4-442b-844f-44t92f17n67s', 
    @Value8 VARCHAR(200) = '02jfgg55savolhffr1mkjf45', 
    @value10 INT = 1, 
    @Option2 BIT = 0, 
    @Value9 VARCHAR(20) = null, 
    @Option1 BIT = 0 

insert into dbo.OurTable 
(
    Type1 
    ,Type2 
    ,Value1 
    ,Value2 
    ,Value3 
    ,Value4 
    ,Date1 
    ,Date2 
    ,Value5 
    ,Value6 
    ,Type3 
    ,Value7 
    ,Type4 
    ,Type5 
    ,Type6 
    ,Type7 
    ,Type8 
    ,Type9 
    ,value10 
    ,Col1 
    ,Col2 
    ,Col3 
    ,Col4 
    ,Value8 
    ,Option2 
    ,Value9 
) 
values 
(
    CASE 
     WHEN [dbo].[GetType](@Type1, null) = 6 AND @Option1 = 1 AND [dbo].[GetType](@Type4, 0) <> 1 
     THEN 7 
     ELSE [dbo].[GetType](@Type1, null) 
    END 
    ,[dbo].[GetType](@Type2, null) 
    ,case when @Value1 = 'null' then null else CAST(@Value1 as numeric(18, 6)) end 
    ,case when @Value2 = 'null' then null else CAST(@Value2 as numeric(18, 6)) end 
    ,case when @Value3 = 'null' then null else CAST(@Value3 as numeric(18, 6)) end 
    ,case when @Value4 = 'null' then null else CAST(@Value4 as numeric(18, 6)) end 
    ,[dbo].[GetDate](@Date1, null) 
    ,[dbo].[GetDate](@Date2, null) 
    ,@Value5 
    ,@Value6 
    ,[dbo].[GetType](@Type3, null) 
    ,case when @Value7 = 'null' then null else CAST(@Value7 as numeric(18, 6)) end 
    ,[dbo].[GetType](@Type4, null) 
    ,@Type6 
    ,case when LOWER(@Type7) = 'null' then null else @Type7 end 
    ,@Type5 
    ,@Type9 
    ,@Type8 
    ,@value10 
    ,GETDATE() 
    ,GETDATE() 
    ,[dbo].[GetGuid](@Guid1) 
    ,[dbo].[GetGuid](@Guid1) 
    ,@Value8 
    ,@Option2 
    ,case when @Value9 = 'null' then null else CAST(@Value9 as int) end 
) 

如果我運行在一個交易這個語句,然後提交我得到10233行屬於該會議前查詢sys.dm_tran_locks。

SELECT * 
FROM sys.dm_tran_locks l 
WHERE l.resource_type <> 'DATABASE' AND l.request_session_id = 65 

65是測試時我當前窗口的會話ID。

另外,如果我看錶鎖(這是我的死鎖的原因),我可以看到它將放在表上的一個X鎖OurTable。

resource_type resource_associated_entity_id Name resource_lock_partition request_mode request_type request_status 
OBJECT 290100074 OurTable 0 X LOCK GRANT 
OBJECT 290100074 OurTable 1 X LOCK GRANT 
OBJECT 290100074 OurTable 2 X LOCK GRANT 
OBJECT 290100074 OurTable 3 X LOCK GRANT 
OBJECT 290100074 OurTable 4 X LOCK GRANT 
OBJECT 290100074 OurTable 5 X LOCK GRANT 
OBJECT 290100074 OurTable 6 X LOCK GRANT 
OBJECT 290100074 OurTable 7 X LOCK GRANT 
OBJECT 290100074 OurTable 8 X LOCK GRANT 
OBJECT 290100074 OurTable 9 X LOCK GRANT 
OBJECT 290100074 OurTable 10 X LOCK GRANT 
OBJECT 290100074 OurTable 11 X LOCK GRANT 
OBJECT 290100074 OurTable 12 X LOCK GRANT 
OBJECT 290100074 OurTable 13 X LOCK GRANT 
OBJECT 290100074 OurTable 14 X LOCK GRANT 
OBJECT 290100074 OurTable 15 X LOCK GRANT 

,或者如果這樣做是由於lock escalation我不知道,如果它從開始在桌子上請求一個排它鎖。無論如何,這會導致我陷入死鎖的困境。

的原因有單個表上的16個鎖定行是因爲lock partitioning.

我的問題是,爲什麼沒有申請表上的意向排他鎖(IX)?相反,它要求獨佔鎖定。我如何防止這種情況?我在調音顧問中沒有收到任何調音提示,我已經試過了。

編輯 在OurTable上有一個插入觸發器,用於更新OurTable3上的字段。它看起來像這樣:

UPDATE OurTable3 SET Date1 = NULL 
    FROM OurTable3 as E 
     JOIN OurTable2 as C on E.Id = C.FKId 
     JOIN OurTable as ETC on ETC.FKId = C.Id 
      AND (ETC.Date2 IS NULL OR CAST(ETC.Date2 AS DATE) > E.Date1) 
      AND ETC.Type1 = 1 

正如你可以看到它不更新OurTable但爲了在OurTable3更新正確的行查詢OurTable。

+1

你看過事務隔離級別了嗎? http://msdn.microsoft.com/en-us/library/ms173763。aspx – dash

+1

是否有可能所有這些函數引用'OurTable'呢?你在那裏運行很多功能... – JNK

+1

什麼是表格結構?你有一個集羣密鑰? –

回答

10

我找到了答案。我們團隊的開發人員有點失誤(我總是責怪其他人:-)。 我應該已經知道答案了,因爲馬丁史密斯在另一個問題中指出我應該檢查ALLOW_ROW_LOCKS和ALLOW_PAGE_LOCKS。但那時我們認爲partitionid與索引id相關,我只檢查了那個索引。

我所做的是用相同的數據創建一個新表。效果消失了,我只在新表上有正確的IX鎖。然後,我創建了每個創作之間的每個索引並進行測試,直到我突然再次產生效果。

我發現這個指數OurTable:

CREATE NONCLUSTERED INDEX [IX_OurTable] ON [dbo].[OurTable] 
(
    [Col1] ASC, 
    [Col2] ASC, 
    [Col3] ASC, 
    [Col4] ASC, 
    [Col5] ASC 
) 
INCLUDE ([Col6], 
[Col7], 
[Col8], 
[Col9]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = OFF, ALLOW_PAGE_LOCKS = OFF, FILLFACTOR = 90) ON [PRIMARY] 
GO 

隨着ALLOW_ROW_LOCKS = OFF和ALLOW_PAGE_LOCKS = OFF很明顯我們將對插入,也是選擇這種效果。

非常感謝您的評論,非常感謝Martin幫我解決了這些死鎖問題。

+1

感謝您分享您的解決方案,似乎是一個棘手的問題,我相信你的文章會幫助別人。 – jpierson