为什么DbSet.Add工作这么慢? [英] Why does DbSet.Add work so slow?

查看:144
本文介绍了为什么DbSet.Add工作这么慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

8个月前在这里讨论了相同的主题:如何加快速度DbSet.Add()?.除了使用SqlBulkCopy之外,没有提出其他解决方案,这对我们来说是不可接受的.我已决定再次提出该建议,希望对此问题可能有新的想法和想法,并提出其他解决方法.至少我很好奇为什么此操作需要这么长时间才能运行.

The same topic was discussed here 8 months ago: How do I speed up DbSet.Add()?. There was no solution proposed other than using SqlBulkCopy which is not acceptable for us. I've decided to bring it up once again hoping there might be new thoughts and ideas around this issue and other workarounds are proposed. At least I'm just curious why this operation takes so long time to run.

好吧,问题是:我必须将3万个实体更新到数据库(EF 4.1,POCO)中.实体类型非常简单,包含整数Id +其他4个整数属性,与其他类型无关. 2例:

Well, the problem is: I have to update 30K entities into database (EF 4.1, POCO). The entity type is quite simple containing integer Id + other 4 integer properties with no relations to other types. 2 cases:

  • 所有这些都是新记录.使用Cntx.Configuration.AutoDetectChangesEnabled = false(true值使其永久运行),每个实体一个一个运行context.Entities.Add(entity)花费90秒.然后,SaveChanges仅花费一秒钟.其他方法:像这样将其附加到上下文需要花费90秒钟的时间:

  • all them are new records. Running context.Entities.Add(entity) one by one for every entity takes 90 seconds with Cntx.Configuration.AutoDetectChangesEnabled=false (true value makes it run forever). Then SaveChanges takes just a second. Other approach: attaching it to the context like this takes the same 90 sec:

Cntx.Entities.Attach(entity);
Cntx.Entry(entity).State = EntityState.Added;

  • 所有这些都是现有记录,但有一些更改.在这种情况下,只需几毫秒即可将其附加到现有的数据上下文中,如下所示:

  • all them are existing records with some changes. In the case it takes just few milliseconds to attach it to existing data context like this:

    Cntx.Entities.Attach(entity);
    Cntx.Entry(entity).State = EntityState.Modified;
    

    看到区别了吗?

    Add方法的幕后花絮使它如此缓慢地工作了吗?

    What is behind the scene of Add method that makes it work so incredibly slow?

    推荐答案

    我得到了有趣的性能测试结果,并且找到了罪魁祸首.我从未读过的任何EF资料中都没有看到类似的信息.

    I've got interesting performance testing results and I've found a culprit. I have not seen any information like this in any EF source I've ever read.

    事实证明是在基类中重载了Equals.基类应该包含在所有类型的具体实体之间共享的Id属性.许多EF书籍都推荐这种方法,并且众所周知.例如,您可以在这里找到它:如何最好地实现自定义类型的等于?

    It turns out to be Equals overridden in a base class. The base class supposed to contain Id property shared between all types of concrete entities. This approach recommended by many EF books and pretty well know. You can find it here for example: How to best implement Equals for custom types?

    更确切地说,取消装箱操作(对象到具体类型的转换)会降低性能,从而使工作如此缓慢.当我评论这行代码时,花了3秒钟才跑了90秒钟!

    More exactly, performance is killed by unboxing operation (object to concrete type conversion) that made it work so slow. As I commented this line of code it took 3 sec to run opposing to 90 sec before!

    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个对象Ids比较)放入扩展方法中,以在具体实体类之间共享并按如下方式运行它:Equal((EntityBase)ConcreteEntityClass).最有趣的是,这个IEquatable可以加快EntitySet的速度.添加6倍!

    As I found it I started thinking over what might be an alternative to this Equals. First idea was to implement IEquatable for EntityBase, but it happened not to be run at all. So what I decided finally to do is to implement IEquatable for each concrete entity class in my model. I have only few of them, so it's minor update for me. You can put whole Equal operation functionality (usually it is 2 object Ids comparison) into extension method to share between concrete entity classes and run it like this: Equal((EntityBase)ConcreteEntityClass). The most interesting, this IEquatable speeds up EntitySet.Add 6 times!

    因此,我不再遇到性能问题,相同的代码可以在不到一秒钟的时间内为我运行. 我的性能提高了180倍!太神奇了!

    So I have no more issues with performance, the same code runs for me with less than a second. I got 180 times performance gain! Amazing!

    结论:

    1. 运行EntitySet.Add的最快方法是使特定实体的IEquatable(0.5秒)
    2. 缺少IEquatable使其运行3秒.
    3. 大多数来源建议具有Equals(object obj)使其运行90秒

    这篇关于为什么DbSet.Add工作这么慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆