小编典典

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

all

我正在寻找插入实体框架的最快方法。

我之所以问这个问题,是因为您有一个活动TransactionScope并且插入量很大(4000+)。它可能持续超过 10
分钟(事务的默认超时),这将导致事务不完整。


阅读 79

收藏
2022-03-02

共1个答案

小编典典

对于您在问题评论中的评论:

“…SavingChanges( 每条记录 )…”

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

  • 在所有记录后调用SaveChanges()一次。
  • SaveChanges()例如,在 100 条记录之后调用。
  • 调用SaveChanges()例如 100 条记录并处理上下文并创建一个新记录。
  • 禁用更改检测

对于批量插入,我正在尝试使用这样的模式:

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 分钟的时间内运行。

对于性能,重要的是SaveChanges()在“许多”记录之后调用(“许多”在 100 或 1000 左右)。它还提高了在 SaveChanges
之后处理上下文并创建新上下文的性能。这会清除所有实体的上下文,SaveChanges但不会这样做,实体仍附加到 state
中的上下文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
个实体处。)这种非线性行为在所有其他测试中并不那么重要。

2022-03-02