为什么在EF 4.1中插入实体与ObjectContext相比如此之慢?
基本上,我在一个事务中插入35000个对象:
using(var uow = new MyContext()){ for(int i = 1; i < 35000; i++) { var o = new MyObject()...; uow.MySet.Add(o); } uow.SaveChanges(); }
这需要永远! 如果我使用底层ObjectContex
t(通过使用IObjectAdapter
),它仍然很慢,但大约需要20 IObjectAdapter
。 它看起来像DbSet<>
正在做一些线性search,这需要平方米的时间…
其他人看到这个问题?
正如Ladislav在评论中指出的那样,您需要禁用自动更改检测以提高性能:
context.Configuration.AutoDetectChangesEnabled = false;
此更改检测在DbContext
API中默认启用。
DbContext
与ObjectContext
API行为如此不同的原因是,在启用自动更改检测时, DbContext
API的更多function将在内部调用DetectChanges
不是ObjectContext
API的函数。
这里您可以find默认调用DetectChanges
的函数列表。 他们是:
-
DbSet
上的Add
,Attach
,Find
,Local
或Remove
成员 -
GetValidationErrors
,Entry
或SaveChanges
成员 -
DbChangeTracker
上的Entries
方法
特别是Add
呼叫DetectChanges
,这是你经历的糟糕的performance负责。
与此相反, ObjectContext
API仅在SaveChanges
自动调用DetectChanges
,而不是在AddObject
和上面提到的其他相应方法中调用DetectChanges
。 这就是为什么ObjectContext
的默认性能更快的原因。
为什么他们在DbContext
中引入这个默认的自动变更检测function呢? 我不确定,但似乎禁用它,并在适当的点手动调用DetectChanges
被认为是先进的,并可以轻松地引入微妙的错误到您的应用程序,所以使用[它]小心 。
EF 4.3 CodeFirst的经验不多的testing:
使用AutoDetectChanges = true删除了1000个对象:23秒
使用AutoDetectChanges = false删除了1000个对象:11秒
用AutoDetectChanges = true插入1000个对象:21秒
用AutoDetectChanges = false插入1000个对象:13秒
在.netcore 2.0中,这被移动到:
context.ChangeTracker.AutoDetectChangesEnabled = false;
除了你在这里find的答案。 知道在数据库级别插入比添加更多的工作是很重要的。 数据库必须扩展/分配新的空间。 然后它必须至less更新主键索引。 尽pipe索引在更新时也可能会更新,但是这种情况并不常见。 如果有任何外键需要读取这些索引以确保参照完整性得以维持。 触发器也可以发挥作用,尽pipe这些也会以同样的方式影响更新。
所有这些数据库工作在由用户条目产生的每日插入活动中是有意义的。 但是,如果你只是上传一个现有的数据库,或者有一个进程产生大量的插入。 你可能想看看如何加快速度,推迟到最后。 通常在插入时禁用索引是常用的方法。 有很复杂的优化,可以根据情况做,他们可以有点压倒一切。
只要知道一般来说,插入将比更新花费更长的时间。