我使用Entity Framework 6.1,MVC5,ASP.NET 4.5和Azure网站(免费)+ Azure SQL。
当我尝试删除45 000个实体时,需要45分钟以上。我的实体中有导航属性。
我试过了:
context.Contacts.RemoveRange(db.Groups.Find(id).Contacts.ToList());
而且:
foreach(var contact in db.Groups.Find(id).Contacts.ToList())
{
context.Database.ExecuteSqlCommand("DELETE FROM Contacts WHERE ContactID = {0}", contact.ContactID);
}
我确定这不正常......但是造成这个问题的原因是什么?
答案 0 :(得分:0)
当您呼叫.ToList()
时,您将所有这些实体撤回到内存中以便开始。然后通过循环遍历这些,如果我了解你的情况,你就可以有效地调用相同的SQL 45000次。
您不需要返回整个对象来删除它。我建议只需在查询中选择ID即可删除要删除的联系人的ID:
var ids = db.Groups.Find(id).Contacts.Select(x => x.ContactId).ToList();
然后我会考虑实现EntityFrameworkExtensions库(https://github.com/loresoft/EntityFramework.Extended)来帮助处理这个问题(确保批量删除),或者使用IN查询,例如DELETE FROM Contacts WHERE ContactID IN (1,2,3,....)
但是再次确保批处理。
Extensions库允许您执行删除操作:
m_context.Contacts.Delete(x => idList.Contains(x.ContactId));
但请注意,这将立即执行,而不是在您致电SaveChanges()
总体而言,代码将是这样的:
public int RemoveContacts(IList<int> _ids)
{
int index = 0;
int numDeleted = 0;
while (index < _ids.Count())
{
var batch= _ids.Skip(index).Take(MAX_BATCH_SIZE);
//Using extensions method
numDeleted += context.Contacts.Delete(x => batch.Contains(x.ContactId));
//Using SQL
context.Database.ExecuteSqlCommand("DELETE FROM Contacts WHERE ContactID IN {0}", batch);
index += MAX_BATCH_SIZE;
}
return numDeleted ;
}