entity framework5性能不佳

我有5个实体:

public class Album { public int Id { get; set; } public string Title { get; set; } public virtual List AlbumArtists { get; set; } public virtual List Artists { get; set; } public virtual List Genres { get; set; } public virtual List Songs { get; set; } } public class AlbumArtist { public int Id { get; set; } public string Title { get; set; } public virtual List Albums { get; set; } public virtual List Artists { get; set; } public virtual List Genres { get; set; } public virtual List Songs { get; set; } } public class Artist { public int Id { get; set; } public string Title { get; set; } public virtual List AlbumArtists { get; set; } public virtual List Albums { get; set; } public virtual List Genres { get; set; } public virtual List Songs { get; set; } } public class Genre { public int Id { get; set; } public string Title { get; set; } public virtual List AlbumArtists { get; set; } public virtual List Albums { get; set; } public virtual List Artists { get; set; } public virtual List Songs { get; set; } } public class Song { public int Id { get; set; } public string Title { get; set; } public virtual List AlbumArtists { get; set; } public virtual List Albums { get; set; } public virtual List Artists { get; set; } public virtual List Genres { get; set; } } 

如您所见,有很多多对多的关系。 我填充我的实体,然后尝试以这种方式将它们保存到DbContext:

 _albumArtists.ForEach(delegate(AlbumArtist albumArtist) { if (albumArtist.Id == 0) { _dbContext.Entry(entity).State = EntityState.Added; _dbContext.SaveChanges(); } else { _dbContext.Entry(entity).State = EntityState.Modified; _dbContext.SaveChanges(); } }); ... 

或以这种方式:

 _albumArtists.ForEach(delegate(AlbumArtist albumArtist) { if (albumArtist.Id == 0) { _dbContext.Entry(entity).State = EntityState.Added; } else { _dbContext.AlbumArtists.State = EntityState.Modified; } }); _dbContext.SaveChanges(); ... 

将我的实体保存到DbContext需要永远。 我甚至试图做以下事情:

 Configuration.AutoDetectChangesEnabled = false; 

但它没有帮助。 顺便说一下,大约有17000首歌曲和1 700张专辑。

怎么了???

请帮忙!

PS

这是我的完整代码: https : //github.com/vjacheslavravdin/PsyTrance/blob/master/PsyTrance/Program.cs也许您可以建议如何简化它。

谢谢!

首先澄清几点:

对于基于批处理的操作,EF并不比其他方法慢得多。 在我的测试中,使用原始SQL命令可以获得50%的改进,使用SQL批量复制可能会提高10倍,但作为一般规则,EF并不比比较方法慢得多(尽管通常被认为非常慢)。 对于大多数应用,在给定正确调整的情况下,即使在批处理方案中,EF也会提 (请参阅我的文章: http : //blog.staticvoid.co.nz/2012/3/24/entity_framework_comparative_performance和http://blog.staticvoid.co.nz/2012/8/17/mssql_and_large_insert_statements )

由于EF确实改变跟踪的方式,它有可能远远超过大多数人编写基于SqlCommand的插入语句的性能(有很多与查询规划,往返和交易相关的空洞很难写最佳地执行批量插入语句)。 我在这里提出了对EF的这些补充( http://entityframework.codeplex.com/discussions/377636 ),但还没有实现它们。

您决定关闭自动检测更改是完全正确的,每个.Add或.Attach操作都会检测到更改,并枚举跟踪图,因此如果您在相同的上下文中添加17k添加,则需要枚举图17000时间超过17000 + 16999 + … + 2 + 1 = 144,500,000个实体,难怪它花了这么长时间吧? (参见我的文章: http : //blog.staticvoid.co.nz/2012/5/7/entityframework_performance_and_autodetectchanges )

保存更改总是需要枚举跟踪图(它会在内部调用检测更改),因此您的第一种方式将会变慢,因为它实际上将执行与上述相同数量的跟踪调用。

第二种方式要好得多,但它仍然有一个相当大的缺陷,我想这是双重的,首先,当你去保存更改时图表非常大(更大的图表具有指数级更高的跟踪时间),其次它将占用一个因为EF存储了每个实体的两个副本,所以很多内存可以立即保留整个图形。

更好的方法是将图表保存在块中。 一些

 //With Auto detect changes off. foreach(var batch in batches)//keep batch size below 1000 items, play around with the numbers a little { using(var ctx = new MyContext())//make sure you create a new context per batch. { foreach(var entity in batch){ ctx.Entities.Add(entity); } ctx.SaveChanges(); } } 

我希望你的目标应该是17-30秒左右,以完成所有17k行。

通过使用原始SQL命令执行此操作,您可以将其设置为大约12-20秒;

通过重新实现批量复制,您可以将其降低到2-5秒