在实体框架中插入的最快方式

我正在寻找插入Entity Framework的最快方式。

我问这是因为你有一个活跃的TransactionScope的场景,插入是巨大的(4000+)。 它可能会持续超过10分钟(事务的默认超时),并且这将导致不完整的事务。


要对你的问题发表评论:

“... SavingChanges( 对于每个记录 )...”

这是你能做的最糟糕的事! 为每个记录调用SaveChanges()会极大地降低批量插入的速度。 我会做几个简单的测试,这很可能会提高性能:

  • 在ALL记录后调用SaveChanges()一次。
  • 在例如100条记录之后调用SaveChanges()
  • 在例如100条记录之后调用SaveChanges()并处理上下文并创建一个新的上下文。
  • 禁用更改检测
  • 对于批量插入,我正在尝试使用如下模式:

    using (TransactionScope scope = new TransactionScope())
    {
        MyDbContext context = null;
        try
        {
            context = new MyDbContext();
            context.Configuration.AutoDetectChangesEnabled = false;
    
            int count = 0;            
            foreach (var entityToInsert in someCollectionOfEntitiesToInsert)
            {
                ++count;
                context = AddToContext(context, entityToInsert, count, 100, true);
            }
    
            context.SaveChanges();
        }
        finally
        {
            if (context != null)
                context.Dispose();
        }
    
        scope.Complete();
    }
    
    private MyDbContext AddToContext(MyDbContext context,
        Entity entity, int count, int commitCount, bool recreateContext)
    {
        context.Set<Entity>().Add(entity);
    
        if (count % commitCount == 0)
        {
            context.SaveChanges();
            if (recreateContext)
            {
                context.Dispose();
                context = new MyDbContext();
                context.Configuration.AutoDetectChangesEnabled = false;
            }
        }
    
        return context;
    }
    

    我有一个测试程序,向数据库中插入560.000个实体(9个标量属性,无导航属性)。 有了这个代码,它在不到3分钟内就可以工作。

    对于性能,重要的是在“许多”记录(“100”或1000左右的“许多” SaveChanges()之后调用SaveChanges() )。 它还提高了在SaveChanges之后处理上下文的性能并创建一个新的上下文。 这将清除所有实体的上下文, SaveChanges不会这样做,实体仍以Unchanged状态附加到上下文。 在上下文中,连接实体的规模在不断增大,逐步减慢插入。 所以,在一段时间后清除它是有帮助的。

    以下是我的560.000个实体的一些测量值:

  • commitCount = 1,recreateContext = false: 很多小时 (这是你当前的过程)
  • commitCount = 100,recreateContext = false: 超过20分钟
  • commitCount = 1000,recreateContext = false: 242秒
  • commitCount = 10000,recreateContext = false: 202秒
  • commitCount = 100000,recreateContext = false: 199秒
  • commitCount = 1000000,recreateContext = false: 内存不足异常
  • commitCount = 1,recreateContext = true: 超过10分钟
  • commitCount = 10,recreateContext = true: 241秒
  • commitCount = 100,recreateContext = true: 164秒
  • commitCount = 1000,recreateContext = true: 191秒
  • 上面第一个测试中的行为是性能非常非线性,并且随着时间的推移极端降低。 (“许多小时”是一个估计,我从未完成这个测试,20分钟后我停在了50.000个实体。)在所有其他测试中,这种非线性行为并不那么重要。


    这种组合提高了速度。

    context.Configuration.AutoDetectChangesEnabled = false;
    context.Configuration.ValidateOnSaveEnabled = false;
    

    最快的方法是使用我开发的批量插入扩展。

    它使用SqlBulkCopy和自定义数据读取器来获得最佳性能。 因此它比使用常规插入或AddRange快20多倍 EntityFramework.BulkInsert与EF AddRange

    用法非常简单

    context.BulkInsert(hugeAmountOfEntities);
    
    链接地址: http://www.djcxy.com/p/5733.html

    上一篇: Fastest Way of Inserting in Entity Framework

    下一篇: How can I get Id of inserted entity in Entity framework?