2015-11-09 109 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);