实体框架:AddOrUpdate()与循环Add()的性能

时间:2017-06-13 15:52:44

标签: c# entity-framework

假设我有一个10,000个对象的集合,我需要使用Entity Framework添加到数据库中(我认识到EF并不适合这个任务,但让我们用它来运行它现在)。出于这个问题的目的,我们将做出以下假设:

  1. 只有一个表,主键为IDENTITY
  2. 表格是空的。
  3. 对象很简单 - 一切都是原始数据类型(int,bool,string等)
  4. 我可以通过以下两种方式之一在Entity Framework中执行此操作:

    // Option 1
    foreach (var item in largeCollection)
    {
        _context.SomeTable.Add(item);
    }
    
    _context.SaveChanges();
    
    // Option 2
    _context.SomeTable.AddOrUpdate(largeCollection);
    _context.SaveChanges();
    

    一种方法的表现本质上是好还是差?或者它们是否都转换为相同数量的单行INSERT语句?

    换句话说,从性能的角度来看,在将多个项目插入数据库时​​,使用Add()优先于AddOrUpdate()(或反之亦然)是否有任何优势?

2 个答案:

答案 0 :(得分:1)

所以这个问题简要讨论了"更新" vs a" insert"就数据库命令而言:

Cost of Inserts vs Update in SQL Server

此外,根据官方MSDN文档(https://msdn.microsoft.com/en-us/library/hh846520(v=vs.103).aspx),添加或更新执行所谓的" upsert"这基本上是一种奇特的说法,如果它存在则更新该行,如果它不存在则插入该行。

现在有了这些信息,Add()是更好的方法似乎是合乎逻辑的。此外,鉴于此特定应用程序最初用于填充数据库(如果我在这个假设上错了请纠正我),似乎做AddOrUpdate()毫无意义,因为没有什么可以更新

答案 1 :(得分:1)

最好的答案是使用AddRange。然而, 通过FAR方式添加比AddOrUpdate更高效。

<强> AddOrUpdate

对每个实体执行数据库往返,以检查它是否已存在于目标表中。

因此,即使您的表为空,如果在10,000个对象上使用AddOrUpdate,也会执行10,000个数据库往返以检查数据是否存在。

添加

Add方法将在更改跟踪器中添加实体,并在添加每条记录后调用DetectChanges方法。

因此,如果添加10,000个对象,则会调用DetectChanges方法10,000次,如果您有一些关系,则可能需要1分钟以上

请参阅:Performance-Add

<强>的AddRange

AddRange方法将添加所有实体,并在添加所有实体后调用DetectChanges方法。

因此,如果添加10,000个对象,则会调用一次DetectChanges方法。

_context.SomeTable.AddRange(largeCollection);

在所有这些情况下,一旦您调用SaveChanges,将执行10,000次额外的数据库往返以保存实体,这些实体也可能非常慢。

免责声明:我是该项目的所有者Entity Framework Extensions

(此库不是免费的)

通过允许您一次保存多个实体,此库可以提高您的代码效率。支持所有批量操作:

  • BulkSaveChanges
  • BulkInsert
  • BulkUpdate
  • BulkDelete
  • BulkMerge
  • BulkSynchronize

示例:

// Easy to use
context.BulkSaveChanges();

// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);

// Perform Bulk Operations
context.BulkDelete(customers);
context.BulkInsert(customers);
context.BulkUpdate(customers);

// Customize Primary Key
context.BulkMerge(customers, operation => {
   operation.ColumnPrimaryKeyExpression = 
        customer => customer.Code;
});