LINQ SaveChanges()异常缓慢

时间:2016-05-31 09:15:32

标签: c# linq visual-studio linq-to-entities edmx

我有一个控制台行应用程序,通过LINQ将大约150,000行保存到数据库中。这工作正常(我通常希望它停止工作)。从CSV文件读取数据后,这是一个沼泽标准保存更改调用: -

 List<Invoice> oldInvoices = db.Invoices.Where(x => !x.IsVisible).ToList();
 List<int> oldInvoiceIDs = oldInvoices.Select(s => s.InvoiceID).ToList();

 List<InvoiceProduct> allInvoiceProducts = db.InvoiceProducts.ToList();
 List<InvoiceProduct> oldInvoiceProducts = allInvoiceProducts.Where(x => oldInvoiceIDs.Contains(x.InvoiceID)).ToList();

 db.InvoiceProducts.RemoveRange(oldInvoiceProducts);
 db.Invoices.RemoveRange(oldInvoices);

 UpdateConsole.WriteLine("Switching over invoices completed. Please wait...", ConsoleColor.Black, ConsoleColor.Magenta);

该表是一张发票清单,其中包含针对每张发票的子链接产品表。每次我们获取新数据时,我们写入新数据,在数据库中将其标记为不可见,然后将当前可见数据切换为不可见,将当前不可见数据切换为可见数据,从而实现从一个数据集立即切换到下一个数据集。刚被标记为不可见的数据集将通过LINQ删除。

这需要花时间删除,但不是一段不合理的时间。由于此数据来自CSV数据文件,因此我们记录行数,以及读取文件的开始和结束日期和时间。这存储在另一个数据库表中,要保存的代码是: -

importLog.SuccessfullyImportedRows = successfulRows;
importLog.FailedImportedRows = failedRows;
importLog.EndTime = DateTime.Now;

db.SaveChanges();

此保存,超过40分钟,我不知道为什么。我唯一能想到的是它使用的是在Visual Studio中生成EDMX时可用的相同DBEntities类?

有人有这个吗?它使应用程序的外观悬挂,但它会在40分钟后继续...

3 个答案:

答案 0 :(得分:1)

您的方法中存在多个性能问题:

  1. 从数据库中拖动不必要的数据。
  2. 批量插入巨大记录。
  3. 从Hude Records批量删除。
  4. 无需从数据库中拖出所有发票,然后在内存中本地过滤它们,您可以直接在数据库中查询并仅检索所需的列表。

    你需要替换它:

     List<InvoiceProduct> allInvoiceProducts = db.InvoiceProducts.ToList();
     List<InvoiceProduct> oldInvoiceProducts = allInvoiceProducts.Where(x => oldInvoiceIDs.Contains(x.InvoiceID)).ToList();
    

    使用:

    List<InvoiceProduct> oldInvoiceProducts = db.InvoiceProducts.Where(x => oldInvoiceIDs.Contains(x.InvoiceID)).ToList();
    

    批量删除更快的方法:

     String commaDelimitedIds = String.Join(",", oldInvoiceIDs);
     String query = "DELETE FROM Invoice WHERE InvoiceID IN (" + commaDelimitedIds + ")";
     db.ExecuteQuery(query);
    

    通过150,000插入Linq To SQL recod并不是一个好主意,这会生成150,000 Insert语句(不提及关系对象)。

    看一下这个例子:SQLBulkCopy,非常适合大量插入。

    一般情况下,ORM 不适合批量操作。

答案 1 :(得分:1)

首先,在您的查询中,我发现使用.toList()时出现问题。 toList表示您强制该查询立即运行并将其存储到内存中。它对于小数据来说速度更快,但对于超过150,000行,肯定会遇到性能问题,并且会出现内存问题。您可以使用AsQueryable()代替。

  

AsQueryable只是创建一个查询,需要获取指令   名单。您可以稍后对查询进行进一步更改,例如添加   新的Where子句一直发送到数据库   水平。

对于EF 6或更高版本,RemoveRange的性能非常快。所以我不认为RemoveRange是这里的根本原因。但是,如果您想提高性能,请尝试使用此扩展程序。这太好了。 https://efbulkinsert.codeplex.com/

答案 2 :(得分:0)

好的,我找到的解决方案(虽然对推理不确定)。如果我不将实体项目带入记录功能,我会从EDMX生成实体的新实例,例如: -

using(DBEntities db = new DBEntities()) {
    importLog.SuccessfullyImportedRows = successfulRows;
    importLog.FailedImportedRows = failedRows;
    importLog.EndTime = DateTime.Now;

    db.SaveChanges();
}

这可以在不到一秒的时间内完成。 DBEntities的原始实例中缓存的内容是否插入了这么多行?