这是 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 支持:
- 选择查询:编写查询并将数据快速输入应用程序非常容易。
- 简化复杂记录的插入。如果您曾经有一个包含很多外键的表,并且您尝试过在一个事务中插入所有链接的记录,您就会知道我在做什么谈论。值得庆幸的是,EF 按顺序插入每条记录,并为您将所有相关记录链接到一个事务中。但如上所述,这是有代价的。
简单地说,如果您有一个操作需要插入一堆记录,那么最好使用SqlBulkCopy。可以在几秒钟内插入数千条记录。
我知道这可能不是您想听到的答案,因为相信我,这也让我感到不安,因为我经常使用 EF,但我看不出有任何解决办法
关于c# - 为什么 Entity Framework 在一个 SaveChanges() 中添加多个项目这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45206015/