我们在实体框架6和SqlSever 2012的数据库第一模型中大量使用Entity Framework。
我们有许多相当长的运行进程(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.WaitAll
Class 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识别被锁定的确切行)。
编辑:deadlock.xdl
EDIT2:在每个删除语句之后调用saveChanges
删除死锁仍然不太明白为什么它会死锁
答案 0 :(得分:8)
您似乎是锁定升级
的受害者为了提高性能,Sql Server(以及所有现代数据库引擎)将许多低级细粒度锁转换为几个高级粗粒锁。在您的情况下,它超过阈值后从行级锁定到完整表锁定。您可以通过以下几种方式解决此问题:
在您的情况下,您调用保存更改的解决方案会导致提交事务并且释放锁定是首选选项。