entity framework批量插入虚幻慢

我正在使用EF 6.我试图插入大约200.000个实体,同时在每100个实体后保存对数据库的更改。

问题是需要11个小时来保存50.000个实体,它仍然落后。 我正在使用WebJobs运行它,并且作业在与主网站相同的azure webapp上发布。 问题是因为和WebJob没有足够的资源,或者在100个实体之后保存,还是方法?

方法

public void SaveLeadsForBuyer(ISenderModel model) { var rowCounter = 0; foreach (var deliveryRecord in model.Customers.Select(customerModel => new DeliveryRecord() { BuyerId = model.Buyer.Id, AspNetUserId = customerModel.Id, DeliveryType = model.Buyer.DeliveryType, CreatedOn = DateTime.UtcNow })) { ++rowCounter; _unit.Repository().Insert(deliveryRecord); _unit.SaveChangesPartially(rowCounter, 100); } _unit.SaveChanges(); } 

帮手

 public static class UnitOfWorkHelper { ///  /// Helper method triggers SaveChanges() after amount of rows provided through "amount" parameter in method ///  /// UnitOfWork object /// Current amount of rows /// Amount when to save changes to database public static void SaveChangesPartially(this IUnitOfWorkAsync unit, int count, int saveCount) { if (count % saveCount == 0) { unit.SaveChanges(); } } } 

它很慢,因为Entity Framework为每条记录执行数据库往返。 因此,如果您节省了200,000个实体,那么将执行200,000次数据库往返 ,这对于保存多个实体来说是最佳的。

对于这种情况,您需要自己实现或使用支持BulkInsert的库(通常在引擎盖下执行SqlBulkCopy)

有3个主库(2个免费,1个PRO)允许批量插入

 // Example from Entity Framework Extensions Library using (var ctx = new EntitiesContext()) { ctx.BulkInsert(list); } 

您可以阅读以下文章来了解每个库的PROS和CONS: entity framework – 批量插入库评论和比较

Entity Framework Extensions是提供最大灵活性的库(Bulk Insert,Update,Delete,Merge和BulkSaveChanges并支持所有内容),但它是PRO版本。 如果您正在寻找免费版本,我建议使用EntityFramework.BulkInsert,但是,它不再受支持,并且不支持所有关联和inheritance。

免责声明 :我是项目entity framework扩展的所有者

编辑:回答评论问题

我保存每100条记录,而不是每条记录

如果向单元上下文添加一个实体或100个实体并不重要,entity framework会逐个保存它们(每个记录都有一个插入语句)。 只需将SQL事件探查器与SQL Server数据库一起使用,您就会明白我的意思。

编辑:回答评论问题

伟大的乔纳森。 有没有办法用ef6通用uow实现这个?

答案取决于您选择使用哪个库。

如果您使用我的库,您可以创建BulkSaveChanges方法或在您的UnitOfWork中更改所有“_context.SaveChanges()”by“_context.BulkSaveChanges()”

 public void SaveLeadsForBuyer(ISenderModel model) { // ... code ... // _unit.SaveChanges(); _unit.BulkSaveChanges(); } 

如果你想从我的库或免费库中获得最佳性能和实现批量插入,我可能会添加名为BulkInsert的方法或扩展方法(如果你不能更改存储库类)

 public class Repository : IRepository where TEntity : class { // ... code ... public virtual void BulkInsert(List list) { _context.BulkInsert(list); } } 

请记住,BulkInsert直接插入实体而不必调用“SaveChanges”,它不使用上下文/更改跟踪器来获得最佳性能。