I was inserting large number of records into database by using Entity Framework with code looking something like this:

void Save()  
{
  foreach(var module in _context.Modules)
  {
    // stuff
    foreach(var type in module.Types)
    {
       // Change properties
    }
  }
  _context.SaveChanges();
}

For anything larger than a few hundres entities it was painfully slow.

SQL Profiler didn't reveal anything helpful as most of the time was spent inside the for loop.

Then I realized that it was related to Entity Framework change tracking and found the best explanation in the blog of Entity Framework team member.

Quick summary is this. EF needs to detect what entities have been changed. It does this by taking an initial snapshot of each entity and then running DetectChanges() method in multiple places. When context tracks many entites, automatic change tracking can be a problem since this code runs in quadratic time.

Here's the solution:

void Save()  
{
  _context.Configuration.AutoDetectChangesEnabled = false;
  foreach(var module in _context.Modules)
  {
    // stuff
    foreach(var type in module.Types)
    {
       // Change properties
    }
  }
  _context.Configuration.AutoDetectChangesEnabled = true;
  _context.SaveChanges();
}

That's it. Two lines. Results were the following:

Number of entities Automatic Change Tracking time(s) Manual Change Tracking time(s)
3 8 8
354 15 9
6085 1350 (yes, that's 22 minutes) 23 (comparing to only 23 seconds)