8 个月前曾在这里讨论过同样的话题:如何加快 DbSet.Add() 的速度? https://stackoverflow.com/questions/4355474/how-do-i-speed-up-dbset-add。除了使用 SqlBulkCopy 之外,没有提出任何解决方案,这对我们来说是不可接受的。我决定再次提出它,希望围绕这个问题可能有新的想法和想法,并提出其他解决方法。至少我只是好奇为什么这个操作需要这么长时间才能运行。
好吧,问题是:我必须将 30K 实体更新到数据库中(EF 4.1,POCO)。实体类型非常简单,包含整数 Id + 其他 4 个整数属性,与其他类型没有关系。 2 例:
-
全部都是新纪录。为每个实体逐一运行 context.Entities.Add(entity) 需要 90 秒,且 Cntx.Configuration.AutoDetectChangesEnabled=false(true 值使其永远运行)。然后 SaveChanges 只需一秒钟。其他方法:像这样将其附加到上下文需要相同的 90 秒:
Cntx.Entities.Attach(entity);
Cntx.Entry(entity).State = EntityState.Added;
-
所有这些都是现有记录,但有一些变化。在这种情况下,只需几毫秒即可将其附加到现有数据上下文,如下所示:
Cntx.Entities.Attach(entity);
Cntx.Entry(entity).State = EntityState.Modified;
看到不同?
Add 方法的幕后原因是什么导致其运行速度如此之慢?
我得到了有趣的性能测试结果,并且找到了罪魁祸首。我在我读过的任何 EF 源中都没有看到过类似的信息。
事实证明,Equals 在基类中被重写了。基类应该包含所有类型的具体实体之间共享的 Id 属性。这种方法被许多 EF 书籍推荐并且广为人知。您可以在这里找到它,例如:如何最好地实现自定义类型的 Equals? https://stackoverflow.com/questions/567642/how-to-best-implement-equals-for-custom-types
更准确地说,拆箱操作(对象到具体类型的转换)会降低性能,导致运行速度如此缓慢。当我评论这行代码时,它需要 3 秒才能运行,而之前需要 90 秒!
public override bool Equals ( object obj )
{
// This line of code made the code so slow
var entityBase = obj as EntityBase;
...
}
当我发现它时,我开始思考什么可以替代这个 Equals。第一个想法是为 EntityBase 实现 IEquatable,但它碰巧根本没有运行。所以我最终决定为模型中的每个具体实体类实现 IEquatable。我只有很少的一些,所以这对我来说只是一个小更新。您可以将整个 Equal 操作功能(通常是 2 个对象 ID 比较)放入扩展方法中,以便在具体实体类之间共享,并像这样运行它:Equal((EntityBase)ConcreteEntityClass)。最有趣的是,这个IEquatable将EntitySet.Add速度提高了6倍!
所以我不再有性能问题,相同的代码在不到一秒的时间内运行。我的性能提升了 180 倍!惊人的!
结论:
- 运行 EntitySet.Add 的最快方法是为特定实体提供 IEquatable(0.5 秒)
- 缺少 IEquatable 会使其运行 3 秒。
- 大多数来源推荐的 Equals(object obj) 使其运行 90 秒
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)