2014-10-02 17 views
0

我知道SQL語句默認情況下不會異步執行,但我有一種似乎表現得那樣的情況。SQL Server似乎以異步方式運行

  • [#data]
  • [tbl_Bucket]
  • [tbl_IDPool]

程序

  • [sp_InsertIntoBucket]
  • [sp_GenerateID]
  • [sp_UpdateIDPool]

過程

  • 應用程序調用[sp_InsertIntoBucket]
  • [sp_InsertIntoBucket]呼叫[sp_GenerateID]
  • [sp_GenerateID]查詢[tbl_IDPool]併產生一值
  • [sp_GenerateID]呼叫[sp_UpdateIDPool]
  • [sp_UpdateIDPool]寫入[tbl_IDPool]
  • [sp_GenerateID]返回其生成的值到[sp_InsertIntoBucket]
  • [sp_InsertIntoBucket]使用該值作爲[tbl_Bucket]
  • 爲一個新的記錄的主鍵
  • [sp_InsertIntoBucket]將生成的值返回給調用者

方案

[#data]有資料 - 往[tbl_Bucket](1500個12000記錄)。由於[sp_InsertIntoBucket]一次只能處理一個記錄,因此該過程被RBAR化 - 對於[#data][sp_InsertIntoBucket]中的每個記錄被調用。

問題

[sp_GenerateID]產生重複的值。在發生[sp_InsertIntoBucket]的實際INSERT併發生錯誤之前,我有13到130個重複生成的值。

所生成的值是依賴於在[tbl_IDPool]數據,因此同樣重要的是[sp_UpdateIDPool]被調用用於每個[sp_GenerateID]呼叫,以確保下一[sp_GenerateID]呼叫生成一個唯一的值。

我懷疑它與[sp_GenerateID]被調用[sp_UpdateIDPool]可以完成寫入[tbl_IDPool]之前被調用。但是這沒有意義,因爲RBAR應該等待[sp_InsertIntoBucket],它應該等待[sp_GenerateID],它應該等待[sp_UpdateIDPool],然後才能轉到下一個[#data]條目,對吧?

我已經試過

  • WAITFOR DELAY "00:00:00.003" - 這工作,但我正在尋找一個更好,更高效,更優雅的解決方案。
  • WHILECURSOR - 唯一的區別是CURSOR稍微慢一些。
  • 有和沒有WITH (NOLOCK)[sp_GenerateID]查詢[tbl_IDPool]希望寫入(第一次調用)會鎖定讀取(第二次調用)。
+1

您應該避免在存儲過程名稱的開頭使用'sp_'。在文檔中有關於爲Microsoft * system *過程保留的警告,如果名稱發生衝突(現在或稍後更新系統),Microsoft會「贏」。 – 2014-10-02 09:49:08

+0

@Damien_The_Unbeliever這很有趣。感謝您的提醒。我沒有意識到這一點,將來會這樣做 - 或者我應該說*不*這樣做。然而,在這種情況下,僅僅是區分實體類型。您的警告已被記錄。 – that0th3rGuy 2014-10-02 10:00:48

+0

你在不同的事務之間有併發,對吧?你爲什麼認爲交易內部存在異步?競爭條件似乎很好地解釋了這種行爲。 – usr 2014-10-02 10:22:50

回答

0

截至[sp_GenerateID]開始嘗試指定

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

然後括在事務塊剩餘的內容。

BEGIN TRANSACTION 
... 
COMMIT TRANSACTION 
+0

感謝您花時間回覆。我嘗試了你在幾個不同的地方建議的陳述,但不斷收到'SERIALIZABLE'附近的錯誤語法。「所以我谷歌搜索並得到這個:http://stackoverflow.com/questions/6342732/tsql-mutual-exclusive-access -in-A-存儲過程 – that0th3rGuy 2014-10-02 10:14:12