2013-11-24 25 views
0

我使用SQL Server 2012的我有一个可重复读事务,我执行此查询:稍后使用INSERT将SELECT COUNT(SomeId)与SomeId相同:适当的锁定策略?

select count(SomeId) 
from dbo.MyTable 
where SomeId = @SomeId 

SomeId是它的值可重复表(认为外键)列。但是,SomeId不是任何索引的成员,也不是外键。

在交易之后,我将记录插入dbo.MyTable具有相同@SomeId,从而改变什么select count(*)将返回被我再次运行它:

insert into dbo.MyTable (SomeId, ...) 
values (@SomeId, ...) 

在我的应用程序可以执行该交易的多个线程与此同时。正因为如此,我在insert声明中出现了死锁。起初,我认为updlock将适用于select声明,但我很快意识到它不会工作,因为我实际上没有更新由select count(SomeId)选择的行。

我的问题是:有没有办法避免潜在的昂贵的表锁?有没有办法锁定涉及SomeId的行,即使它们还没有被插入(奇怪,我知道)?我想强制其他线程等待原始事务完成其工作,但我不想不必要地锁定行。

编辑

这里就是我试图完成:

我只想插入多达八行特定SomeId。有几个不相关的进程可能会同时启动这些事务之一。 select count检测是否已有八行,并导致该操作在该过程中失败。如果计数小于8,那么同一个事务将执行额外的工作,然后在最后插入一条记录,因此select count重新运行时会有效增加计数。我在insert声明中遇到了僵局。

+0

你的描述让我怀疑你可能正在接近这个错误的方式。你能解释一下你试图解决的实际问题吗? –

+0

当然,我会添加更多的上下文。 – NathanAldenSr

+0

我在想'也许在'SomeId'上创建一个索引将是一个不错的选择,然后以某种方式锁定特定'SomeId'的索引。我不熟悉锁定在这个层面上,所以我只是直觉。 :) – NathanAldenSr

回答

0

如果你有几个进程试图做同样的事情,你不想有更多的记录比一些数字,你将需要实际上阻止这些进程在同一时间运行。

一种方法是阅读与排它锁计数:

select count(SomeId) 
from dbo.MyTable with (xlock) 
where SomeId = @SomeId 

这样直到事务完成这些记录将被阻止。

您应该为SomeId列创建一个索引,尽管锁定将很可能以这种方式保持在索引级别上。

+0

我会试试这个。我一直在阅读关于锁定的内容,似乎是为'where列'创建索引的常见建议。 – NathanAldenSr

+0

是的,该指数将有所帮助。不仅用于锁定,还用于选择。 – Szymon

+1

我的开发数据库没有任何索引(PK除外),但我在生产中添加它们。这将是一个例外,因为它有助于执行正确的应用程序行为。 – NathanAldenSr

相关问题