Dot-Net
實體框架死鎖和並發
我們在實體框架 6 和 SqlSever 2012 的數據庫優先模型中大量使用實體框架。
我們有許多相當長的執行程序(10 秒),每個程序都創建一個具有不同數據的相同類型的對象,這些對像在創建過程中使用實體框架在數據庫中寫入和刪除數據。到目前為止,一切都很好。為了提高應用程序的性能,我們希望並行執行這些操作,因此使用
Task構造來實現這一點,如下所示:Private Async Function LongRunningProcessAsync(data As SomeData) As Task(Of LongRunningProcessResult) Return Await Task.Factory.StartNew(Of LongRunningProcessResult)(Function() Return Processor.DoWork(data) End Function) End Function我們執行其中的 10 個並等待它們全部完成使用
Task.WaitAllClass Processor Public Function DoWork(data As SomeData) As LongRunningProcessResult Using context as new dbContext() ' lots of database calls context.saveChanges() end Using ' call to sub which creates a new db context and does some stuff doOtherWork() ' final call to delete temporary database data using yetAnotherContext as new dbContext() Dim entity = yetAnotherContext.temporaryData.single(Function(t) t.id = me.Id) yetAnotherContext.temporaryDataA.removeAll(entity.temporaryDataA) yetAnotherContext.temporaryDataB.removeAll(entity.temporaryDataB) yetAnotherContext.temporaryData.remove(entity) ' dbUpdateExecption Thrown here yetAnotherContext.SaveChanges() end using End Function End Class這在大約 90% 的情況下執行良好,另外 10% 的情況下它會因內部死鎖異常而死鎖數據庫伺服器
所有處理器都使用相同的表,但在程序之間絕對不共享數據(並且不依賴於相同的 FK 行),並創建它們自己的所有實體框架上下文,它們之間沒有共享互動。
查看實例的分析行為,
Sql Server我們看到在每個成功查詢之間有大量非常短暫的鎖獲取和釋放。導致最終的死鎖鏈:Lock:Deadlock Chain Deadlock Chain SPID = 80 (e413fffd02c3) Lock:Deadlock Chain Deadlock Chain SPID = 73 (e413fffd02c3) Lock:Deadlock Chain Deadlock Chain SPID = 60 (6cb508d3484c)鎖本身是類型
KEY的,死鎖查詢都是針對同一個表但具有不同形式的鍵:exec sp_executesql N'DELETE [dbo].[temporaryData] WHERE ([Id] = @0)',N'@0 int',@0=123我們對實體框架相對較新,並且無法確定似乎過度鎖定的根本原因(我無法通過 sql profiler 確定被鎖定的確切行)。
編輯:死鎖.xdl
EDIT2:
saveChanges在每個刪除語句刪除死鎖後呼叫仍然不太明白為什麼它會死鎖
您似乎是鎖升級的受害者
為了提高性能,Sql Server(以及所有現代數據庫引擎)會將許多低級細粒度鎖轉換為一些高級粗粒度鎖。在您的情況下,超過門檻值後,它會從行級鎖變為全表鎖。您可以通過幾種不同的方式解決此問題:
- 一種解決方案是呼叫您已經完成的 SaveChanges()。這將更快地釋放鎖,防止發生鎖升級,因為較低的鎖計數 = 不太可能達到升級門檻值。
- 您還可以將隔離級別更改為未送出的讀取,這將通過允許臟讀來減少鎖的數量,這也將防止發生鎖升級。
- 最後,您應該能夠使用 SET ( LOCK_ESCALATION = { AUTO | TABLE | DISABLE } ) 發送 ALTER TABLE 命令。但是,即使禁用,表級鎖仍然是可能的。MSDN 指向在可序列化隔離級別下掃描沒有聚集索引的表的範例。見這裡: https ://msdn.microsoft.com/en-us/library/ms190273(v=sql.110).aspx
在您的情況下,您呼叫保存更改的解決方案,導致事務被送出並且鎖被釋放是更可取的選擇。