2015-11-09 134 views
0

我正在使用实体框架来构建数据库。有两种模式; 工作人员 and 技能。每个工人有零个或多个技能。我最初从某个CSV文件中将这些数据读入内存,并将其存储在名为allWorkers的字典中。接下来,我将数据写入到数据库这样的:使用实体框架插入很多行非常慢

// Populate database 
using (var db = new SolverDbContext()) 
{ 
    // Add all distinct skills to database 
    db.Skills.AddRange(allSkills 
     .Distinct(StringComparer.InvariantCultureIgnoreCase) 
     .Select(s => new Skill 
     { 
     Reference = s 
     })); 

    db.SaveChanges(); // Very quick 
    var dbSkills = db.Skills.ToDictionary(k => k.Reference, v => v); 

    // Add all workers to database 
    var workforce = allWorkers.Values 
     .Select(i => new Worker 
     { 
     Reference = i.EMPLOYEE_REF, 
     Skills = i.GetSkills().Select(s => dbSkills[s]).ToArray(), 
     DefaultRegion = "wa", 
     DefaultEfficiency = i.TECH_EFFICIENCY 
     }); 

    db.Workers.AddRange(workforce); 
    db.SaveChanges(); // This call takes 00:05:00.0482197 
} 

最后db.SaveChanges();需要五分钟来执行,这我觉得是太长了。我跑SQL Server事件探查器作为呼叫正在执行,并且基本上是我发现了数以千计的电话给:

INSERT [dbo].[SkillWorkers]([Skill_SkillId], [Worker_WorkerId]) 
VALUES (@0, @1) 

有被添加到SkillWorkers 16027行,这是一个相当数量的数据,但没有任何巨大手段。有什么方法可以优化这段代码,所以不需要5分钟运行?

更新:我看了其他可能的重复,such as this one,但我不认为它们适用。首先,我不是在循环中增加任何内容。在每行添加到db.Workers之后,我正在对db.SaveChanges();进行单个调用。这应该是批量插入的最快方式。其次,我已将db.Configuration.AutoDetectChangesEnabled设置为false。现在拨打SaveChanges()需要00:05:11.2273888(换句话说,大致相同)。我不认为这真的很重要,因为每一行都是新的,因此没有变化来检测。

我想我正在寻找的是一种发布包含所有16,000技能的单个UPDATE语句的方法。

+3

您是否尝试过搜索?关于在Entity Framework中批量插入有很多问题,请参阅例如[在实体框架中插入的最快方式](http://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework) 。 – CodeCaster

+0

可能禁用自动检测更改:http://stackoverflow.com/questions/5943394/why-is-inserting-entities-in-ef-4-1-so-slow-compared-to-objectcontext/5943699#5943699 – GendoIkari

+0

看起来像http://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework的副本给我。 – JamieSee

回答

1

一个简单的方法是使用EntityFramework.BulkInsert扩展名。

你可以再做:

// Add all workers to database 
var workforce = allWorkers.Values 
    .Select(i => new Worker 
    { 
     Reference = i.EMPLOYEE_REF, 
     Skills = i.GetSkills().Select(s => dbSkills[s]).ToArray(), 
     DefaultRegion = "wa", 
     DefaultEfficiency = i.TECH_EFFICIENCY 
    }); 

db.BulkInsert(workforce);