[英]Why is inserting entities in EF 4.1 so slow compared to ObjectContext?
Basically, I insert 35000 objects within one transaction:基本上,我在一个事务中插入 35000 个对象:
using(var uow = new MyContext()){
for(int i = 1; i < 35000; i++) {
var o = new MyObject()...;
uow.MySet.Add(o);
}
uow.SaveChanges();
}
This takes forever!这需要永远! If I use the underlying ObjectContex
t (by using IObjectAdapter
), it's still slow but takes around 20s.如果我使用底层ObjectContex
t(通过使用IObjectAdapter
),它仍然很慢,但需要大约 20 IObjectAdapter
。 It looks like DbSet<>
is doing some linear searches, which takes square amount of time...看起来DbSet<>
正在做一些线性搜索,这需要平方的时间......
Anyone else seeing this problem?还有其他人看到这个问题吗?
As already indicated by Ladislav in the comment, you need to disable automatic change detection to improve performance:正如 Ladislav 在评论中已经指出的那样,您需要禁用自动更改检测以提高性能:
context.Configuration.AutoDetectChangesEnabled = false;
This change detection is enabled by default in the DbContext
API.默认情况下,在DbContext
API 中启用此更改检测。
The reason why DbContext
behaves so different from the ObjectContext
API is that many more functions of the DbContext
API will call DetectChanges
internally than functions of the ObjectContext
API when automatic change detection is enabled. DbContext
行为与ObjectContext
API 如此不同的原因是,当启用自动更改检测时, DbContext
API 的更多函数将在内部调用DetectChanges
不是ObjectContext
API 的函数。
Here you can find a list of those functions which call DetectChanges
by default. 在这里您可以找到默认调用DetectChanges
的那些函数的列表。 They are:他们是:
Add
, Attach
, Find
, Local
, or Remove
members on DbSet
DbSet
上的Add
、 Attach
、 Find
、 Local
或Remove
成员GetValidationErrors
, Entry
, or SaveChanges
members on DbContext
该GetValidationErrors
, Entry
,或SaveChanges
上成员DbContext
Entries
method on DbChangeTracker
DbChangeTracker
上的Entries
方法Especially Add
calls DetectChanges
which is responsible for the poor performance you experienced.尤其是Add
调用DetectChanges
,这会导致您遇到的性能不佳。
I contrast to this the ObjectContext
API calls DetectChanges
only automatically in SaveChanges
but not in AddObject
and the other corresponding methods mentioned above.与此相反, ObjectContext
API 仅在SaveChanges
自动调用DetectChanges
,而不在AddObject
和上述其他相应方法中调用。 That's the reason why the default performance of ObjectContext
is faster.这就是ObjectContext
的默认性能更快的原因。
Why did they introduce this default automatic change detection in DbContext
in so many functions?为什么他们在这么多函数中引入了这种默认的DbContext
自动变化检测? I am not sure, but it seems that disabling it and calling DetectChanges
manually at the proper points is considered as advanced and can easily introduce subtle bugs into your application so use [it] with care .我不确定,但似乎禁用它并在适当的点手动调用DetectChanges
被认为是高级的,并且很容易将细微的错误引入您的应用程序,因此请谨慎使用 [it] 。
Little empiric test with EF 4.3 CodeFirst:使用 EF 4.3 CodeFirst 的小经验测试:
Removed 1000 objects with AutoDetectChanges = true : 23 sec使用 AutoDetectChanges = true 删除了 1000 个对象:23 秒
Removed 1000 objects with AutoDetectChanges = false: 11 sec使用 AutoDetectChanges = false: 11 sec 删除了 1000 个对象
Inserted 1000 objects with AutoDetectChanges = true : 21 sec使用 AutoDetectChanges = true 插入 1000 个对象:21 秒
Inserted 1000 objects with AutoDetectChanges = false : 13 sec使用 AutoDetectChanges = false 插入 1000 个对象:13 秒
在 .netcore 2.0 中,这被移至:
context.ChangeTracker.AutoDetectChangesEnabled = false;
Besides the answers you have found here.除了你在这里找到的答案。 It is important to know that at the database level is is more work to insert than it is to add.重要的是要知道在数据库级别插入比添加更多的工作。 The database has to extend/allocate new space.数据库必须扩展/分配新空间。 Then it has to update at least the primary key index.然后它必须至少更新主键索引。 Although indexes may also be updated when updating, it is a lot less common.虽然更新时索引也可能会被更新,但这种情况要少得多。 If there are any foreign keys it has to read those indexes as well to make sure referential integrity is maintained.如果有任何外键,它也必须读取这些索引以确保保持参照完整性。 Triggers can also play a role although those can affect updates the same way.触发器也可以发挥作用,尽管它们可以以相同的方式影响更新。
All that database work makes sense in daily insert activity originated by user entries.所有这些数据库工作在由用户条目发起的日常插入活动中都是有意义的。 But if you are just uploading an existing database, or have a process that generates a lot of inserts.但是如果你只是上传一个现有的数据库,或者有一个生成大量插入的过程。 You may want to look at ways of speeding that up, by postponing it to the end.您可能想通过将其推迟到最后来查看加快速度的方法。 Normally disabling indexes while inserting is a common way.通常在插入时禁用索引是一种常见的方法。 There is very complex optimizations that can be done depending on the case, they can be a bit overwhelming.可以根据情况进行非常复杂的优化,它们可能有点令人难以抗拒。
Just know that in general insert will take longer than updates.只知道通常插入比更新需要更长的时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.