c# - 为什么 Entity Framework 在一个 SaveChanges() 中添加多个项目这么慢?

标签 c# entity-framework entity-framework-6

这是 a previous question 的跟进,其中我试图找出我的代码运行缓慢的主要原因。我想我已经将它缩小到下面的一个最小示例。我有一个基本的数据库结构如下:

public class Foo
{
    public int Id { get; set; }
    public string Bar { get; set; }
}

public class FooContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }
}

现在,如果我有一个 Foo 对象列表,并且想将它们添加到数据库中,建议的方法是使用 AddRange()。但我注意到它需要很长时间,并且受集合中项目数量的影响很小,即使是像 200 这样的小数量。所以我手动写出来,viola,它运行得更快!

class Program
{
    static void Main(string[] args)
    {
        var foos = Enumerable.Range(0, 200).Select(index => new Foo { Bar = index.ToString() });

        // Make sure the timing doesn't include the first connection
        using (var context = new FooContext())
        {
            context.Database.Connection.Open();
        }

        var s1 = Stopwatch.StartNew();
        using (var context = new FooContext())
        {
            context.Foos.AddRange(foos);
            context.SaveChanges();
        }
        s1.Stop();

        var s2 = Stopwatch.StartNew();
        using (var context = new FooContext())
        {
            // Ignore the lack of sanitization, this is for demonstration purposes
            var query = string.Join(";\n", foos.Select(f => "INSERT INTO Foos ([Bar]) VALUES (" + f.Bar + ")"));
            context.Database.ExecuteSqlCommand(query);
        }
        s2.Stop();

        Console.WriteLine("Normal way: {0}", s1.Elapsed);
        Console.WriteLine("Hard way  : {0}", s2.Elapsed);
        Console.ReadKey();
    }
}

我最初的想法是 Entity Framework 可能对每个条目使用单独的事务,但记录 SQL 表明情况并非如此。那么为什么执行时间会有这么大的差异呢?

最佳答案

在对您的问题进行一些研究时,我看到了这篇启发性的文章:http://www.codinghelmet.com/?path=howto/bulk-insert

引用一段话:

Each object that was inserted required two SQL statements - one to insert a record, and additional one to obtain identity of the new record

当插入多条记录时,这会成为一个问题。每个记录一次插入一个事实加剧了这个问题(但这不在您的问题范围内,因为您已经在测试一个接一个的插入)。所以如果你要插入 200 条记录,那就是 400 条 sql 语句被一条一条地执行。

所以根据我的理解,EF 根本不是为批量插入而构建的。哪怕插入200条记录这么简单。这对我来说似乎是一个很大的失望。

我开始思考,“那么 EF 到底有什么用呢。它甚至不能插入几条记录”。好吧,我将在两个方面提供 EF 支持:

  1. 选择查询:编写查询并将数据快速输入应用程序非常容易。
  2. 简化复杂记录的插入。如果您曾经有一个包含很多外键的表,并且您尝试过在一个事务中插入所有链接的记录,您就会知道我在做什么谈论。值得庆幸的是,EF 按顺序插入每条记录,并为您将所有相关记录链接到一个事务中。但如上所述,这是有代价的。

简单地说,如果您有一个操作需要插入一堆记录,那么最好使用SqlBulkCopy。可以在几秒钟内插入数千条记录。

我知道这可能不是您想听到的答案,因为相信我,这也让我感到不安,因为我经常使用 EF,但我看不出有任何解决办法

关于c# - 为什么 Entity Framework 在一个 SaveChanges() 中添加多个项目这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45206015/

相关文章:

c# - 刷新 EntityFramework 连接

c# - Entity Framework 获取缓慢

c# - 如何填充 ItemsControl 中的外键字段?

C# EF 在一个请求中更新实体

c# - 使用相同的 SQL 生成输出将 T-SQL 转换为 Fluent Linq C#

c# - RDP 客户端 - AxHost.InvalidActiveXStateException

c# - 如何将依赖项注入(inject)动态加载的程序集

performance - EF 和 .EDMX 性能注意事项

razor - 无法加载文件或程序集'System.Web.WebPages.Razor,版本 = 3.1.1

c# - 使用 VS 2010 创建的数据库部署网站