C# 实体框架批量插入-创建大量对象/实体是缓慢的部分?

C# 实体框架批量插入-创建大量对象/实体是缓慢的部分?,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,这里和其他地方有很多关于如何使用EF加速批量插入的信息和答案 然而,我只插入了大约10000条记录和创建实体的缓慢部分 首先,我将外部数据保存到一个数据表中,然后循环并为每一行创建一个新的实体,将子实体添加到循环中(源于两个其他数据表),循环完成后,调用db.SaveChanges() 在我的初始评测中,db.SaveChanges()的速度很慢,但与首先创建所有对象的循环相比,没有什么效果-可以作为单独的列表实体或直接到上下文 这正常吗?正如我所看到的批量插入的所有问题一样,大多数问题似乎与对

这里和其他地方有很多关于如何使用EF加速批量插入的信息和答案

然而,我只插入了大约10000条记录和创建实体的缓慢部分

首先,我将外部数据保存到一个数据表中,然后循环并为每一行创建一个新的
实体
,将子实体添加到循环中(源于两个其他数据表),循环完成后,调用
db.SaveChanges()

在我的初始评测中,
db.SaveChanges()
的速度很慢,但与首先创建所有对象的循环相比,没有什么效果-可以作为单独的
列表实体
或直接到上下文

这正常吗?正如我所看到的批量插入的所有问题一样,大多数问题似乎与对数据库的最终提交有关


编辑以添加一些代码请原谅psudo代码

DataTable ref1 = ConvertCSVtoDataTable(csv, firstRowsToDelete: 15); // Return's a Datatable from a CSV

foreach(string file in ListOfFilesToProcess)
{
    DataTable tbl = loadExcelFiles(file);

    foreach(DataRow dr in tbl.Rows)
    {
         Entity newEntity = new Entity();
         Entity.property1 = dr["Property1"].ToString();
         ... // Keep mapping properties to elements in the datatable
         Entity.Child.Add(new ChildEntity() { prop1 = ref1["ChildProp1"].ToString() });
         // Add the newly created entity to the context
         db.Entity.Add(newEntity);
    }
}
// Save the context
db.SaveChanges();
因此,在保存上下文时,有几千个
newEntity
对象及其子
navigation
对象

迭代datatable并创建所有这些对象是最慢的部分


另外,
db.Configuration.AutoDetectChangesEnabled=false已设置。

在“创建所有对象”部分中,缓慢的部分是检测更改

您应该始终使用AddRange而不是Add

  • 添加:检测每个对象的更改
  • AddRange:仅检测一次更改(添加所有对象后)
此代码应修复创建对象时的缓慢部分:

DataTable ref1 = ConvertCSVtoDataTable(csv, firstRowsToDelete: 15); // Return's a Datatable from a CSV

List<Entity> list = new List<Entity>();

foreach(string file in ListOfFilesToProcess)
{
    DataTable tbl = loadExcelFiles(file);

    foreach(DataRow dr in tbl.Rows)
    {
         Entity newEntity = new Entity();
         Entity.property1 = dr["Property1"].ToString();
         ... // Keep mapping properties to elements in the datatable
         Entity.Child.Add(new ChildEntity() { prop1 = ref1["ChildProp1"].ToString() });

        list.Add(newEntity);
    }
}

// Add all newly created entities to the context
db.Entity.AddRange(list);

// Save the context
db.SaveChanges();
DataTable ref1=convertcsvtodatable(csv,firstRowsToDelete:15);//返回的是来自CSV的数据表
列表=新列表();
foreach(ListOfFilesToProcess中的字符串文件)
{
DataTable tbl=loadExcelFiles(文件);
foreach(数据行dr在tbl.行中)
{
实体newEntity=新实体();
Entity.property1=dr[“property1”].ToString();
…//将属性映射到datatable中的元素
添加(新的ChildEntity(){prop1=ref1[“ChildProp1”].ToString()});
列表。添加(新实体);
}
}
//将所有新创建的实体添加到上下文中
db.Entity.AddRange(列表);
//保存上下文
db.SaveChanges();
如果在此修复之后,您仍然存在一些性能问题(这次来自数据库),您应该尝试BulkSaveChanges/BulkInsert第三方库

下面是一篇关于这些库的文章:

  • 实体框架扩展(推荐,支持一切)
  • EntityFramework.BulkInsert
  • EntityFramework.Utilities

免责声明:我是项目的所有者

只需使用批量插入即可。即使您克服了EF糟糕的性能,您仍然必须与不喜欢单个插入的数据库抗争。

发布代码可能有助于其他人理解如果您处理CSV文件,最好不要使用实体框架。无论您使用什么服务器,都可以使用本机加载程序,或者如果您的数据库有批量加载API,最好使用它。@Mike有一个CSV和许多Excel文件。我可以把它们都解析成一个SQL事务,但只需要了解EF及其优缺点。根据这个问题,有大量关于批量插入的缓慢性能的信息,但没有关于创建1000个对象的信息。这只是我的问题,还是每个人都有同样的问题,但他们只是认为这是批量插入?如果有办法把插入时间缩短到几秒钟,那一定是我的错!?使用
AddRange()
我在大约1.3秒内插入了大约10000条记录。如果仍然需要20秒才能完成,这里会发生一些事情。谢谢,
AddRange()
已经产生了巨大的变化,从~20秒下降到毫秒!然而,创建实体列表仍然需要18秒,这仅适用于5200个实体(包含8000个子项)。所以问题仍然存在,为什么创建列表要花这么长时间?只是为了确保我理解,在所有行上循环并创建列表大约需要18秒?(不包括“AddRange”和“SaveChanges”代码所用的时间)。如果是这种情况,您应该在循环中发布完整的代码,以确保我们准确地指出问题所在。没错,在i7、16GB RAM机器上18秒只是为了创建列表-在我们到达
AddRange
之前-有一些反射,还有一些进一步的循环,但调试表明每个循环大约需要7毫秒才能完成。我将尝试将循环提取为可读的内容,否则它们太长,而且大多只是将datatable中的列映射到entities属性。