我正在寻找插入 Entity Framework 的最快方法。
我之所以这样问,是因为您有一个活跃的TransactionScope且插入量很大(超过4000个)。它可能持续10分钟以上(默认的事务超时),这将导致不完整的事务。

最佳答案

在对您的问题的评论中发表评论:



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

  • 在所有记录之后调用一次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不会这样做,实体仍然以Unchanged状态附加到上下文。在上下文中,连接实体的大小不断增长,这会逐步降低插入速度。因此,一段时间后清除它会很有帮助。

    以下是我的560000个实体的一些度量值:
  • 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个实体上。)这种非线性行为在所有其他测试中都不那么重要。

    10-07 21:08