2011-12-05 155 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