2013-11-24 80 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

相關問題