最近,我正在做一些简单的EF工作。非常简单, 首先,
List<Book> books = entity.Books.WHERE(c=>c.processed==false)ToList();
then
foreach(var book in books)
{
//DoSomelogic, update some properties,
book.ISBN = "ISBN " + randomNumber();
book.processed = true;
entity.saveChanges(book)
}
我将entity.saveChanges
放在foreach
中,因为它是一个大型列表,大约有10万条记录,如果这条记录处理没有问题,则标记此记录,设置book.processed = true,如果该过程被异常中断,然后下次,我不必再次处理这些好的记录。
一切似乎都对我好。处理数百条记录时速度很快。然后当我们移动到100k记录时,entity.saveChanges非常慢。每条记录约1-3秒。然后我们保留实体模型,但用经典entity.saveChanges
替换SqlHelper.ExecuteNonQuery("update_book", sqlparams)
。它非常快。
有谁能告诉我为什么实体框架进程那么慢?如果我仍然想使用entity.saveChanges,那么提高性能的最佳方法是什么?
谢谢
答案 0 :(得分:31)
在执行插入操作之前关闭更改跟踪。这将显着改善您的表现(秩序的大小)。将SaveChanges()
置于循环之外也会有所帮助,但关闭更改跟踪将会有所帮助。
using (var context = new CustomerContext())
{
context.Configuration.AutoDetectChangesEnabled = false;
// A loop to add all your new entities
context.SaveChanges();
}
有关详情,请参阅this page。
答案 1 :(得分:7)
我会把foreChanges(书)放在foreach之外。由于book是作为一个列表在实体上,你可以将它放在外面,EF可以更好地使用生成的代码。
列表是实体的属性,EF旨在优化后端数据库上的更新/创建/删除。如果你这样做,我会好奇它是否有帮助。
答案 2 :(得分:4)
我也建议你将SaveChanges()从循环中取出,因为它对数据库进行了大量的更新,因此上下文将有'n'次迭代检查点和所需的验证。
var books = entity.Books.Where(c => c.processed == false).ToList();
books.Foreach(b =>
{
b.ISBN = "ISBN " + randomNumber();
b.processed = true;
//DoSomelogic, update some properties
});
entity.SaveChanges();
答案 3 :(得分:0)
&#34;的 AsNoTracking 强>&#34;适合我
前:
Item itemctx = ctx.Items.AsNoTracking().Single(i=>i.idItem == item.idItem);
ctx.Entry(itemctx).CurrentValues.SetValues(item);
itemctx.images = item.images;
ctx.SaveChanges();
没有&#34; AsNoTracking&#34;更新非常缓慢。
答案 4 :(得分:0)
在我看来,从性能和内存消耗的角度来看,实体框架对于BULK操作来说是一个糟糕的选择。一旦超过几千条记录,SaveChanges方法就会真正开始崩溃。
您可以尝试将您的工作划分为较小的交易,但同样,我认为您正在努力创建此工作。
更好的方法是利用DBMS已经提供的BULK操作。 SQL Server通过.NET提供BULK COPY。 Oracle为Oracle.DataAccess或非托管数据访问提供BULK COPY。对于Oracle.ManagedDataAccess,遗憾的是,BULK COPY库不可用。但我可以使用BULK COLLECT / FOR ALL创建一个Oracle存储过程,允许我在几秒钟内插入数千条记录,并在应用程序中占用更少的内存。在.NET应用程序中,您可以将PLSQL关联数组实现为参数等。
利用DBMS中的BULK工具的好处是减少应用程序,查询处理器和数据库引擎之间的上下文切换。
我确定其他数据库供应商提供类似的东西。
答案 5 :(得分:0)
使用此Nuget软件包: Z.EntityFramework.Extensions
它具有可在DbContext上调用的扩展方法,例如DbContext.BulkSaveChanges,其运行速度惊人。
答案 6 :(得分:0)
我只是直接执行插入命令。
//the Id property is the primary key, so need to have this update automatically
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT[dbo].[MyTable] ON");
foreach (var p in itemsToSave)
{
db.Database.ExecuteSqlCommand("INSERT INTO[dbo].[MyTable]([Property1], [Property2]) VALUES(@Property1, @Property2)",
new SqlParameter("@Property1", p.Property1),
new SqlParameter("@Property2", p.Property2)"
}
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT[dbo].[MyTable] OFF");
工作真的很快。 EF 在批量更新时慢得令人难以置信,在我的情况下完全无法用于十多个项目。