[英]Why is Entity Framework dbSet.Include taking so long to return?
我在表上做一个简单的“获取”,例程的“包含”部分花费的时间比我期望的要长得多。
我将性能问题缩小到以下代码段:
private List<Task> GetFilteredTasksWithOptionalIncludes(EntityRepository<Task> repo, ITaskRequest model, TaskIncludesModel includes, string accountID)
{
var includedEntities = new List<Expression<Func<Task, object>>>();
includedEntities.Add(t => t.Document.Transaction.Account);
includedEntities.Add(p => p.Signature);
if (includes != null)
{
if (includes.IncludeWorkflowActions)
{
includedEntities.Add(p => p.Actions);
}
if (includes.IncludeFileAttachments)
{
includedEntities.Add(p => p.Attachments);
}
}
IQueryable<Task> tasks = repo.GetAllIncluding(includedEntities.ToArray()); //RETURNS SLOW
return tasks.ToList(); //RETURNS FAST
}
我的所有代码运行都非常快,直到达到repo.GetAllInclude方法,如下所示:
public IQueryable<TEntity> GetAllIncluding(params Expression<Func<TEntity, object>>[] includeProperties)
{
foreach (var includeProperty in includeProperties)
{
dbSet.Include(includeProperty).Load();
}
return dbSet;
}
当我逐步执行代码时,GetAllIncluded()行最多需要6或7秒的时间才能返回,但task.ToList()返回的时间不到一秒钟(这是实际的SQL查询运行时,因此这让我感到惊讶)。
当我注释掉加载include的foreach循环时,整个调用在不到一秒的时间内返回。 是什么原因导致包含内容花费这么长时间? 还有更好的方法吗?
如果有帮助,这里是调用周围的SQL事件探查器。 红线上方的所有内容均来自GetAllIncluded调用。 红线下方的所有内容都是对数据的实际查询。 有没有更有效的方法可以做到这一点? 看起来很简单的通话似乎不需要10秒。
当您在该循环中调用.Load()
时,实际上是在访问数据库并将数据放入上下文中。
因此,根据您要执行该循环的频率,您会不断地运行该查询。
我建议删除.Load()
但您仍然可以保留.Load()
函数。 通用存储库的基本“包含”功能如下所示:
public IQueryable<TEntity> Including(params Expression<Func<TEntity, object>>[] _includeProperties)
{
IQueryable<TEntity> query = context.Set<TEntity>();
return _includeProperties.Aggregate(query, (current, includeProperty) => current.Include(includeProperty));
}
一旦调用了此方法并掌握了IQueryable
,只需对其调用.ToList()
即可仅从SQL中提取一次。
阅读http://msdn.microsoft.com/en-gb/data/jj592911.aspx,以了解Load方法的实际作用。
根据您的评论进行编辑:
您可以实现我发布的上述功能,并以与您现在正在使用的方式类似的方式使用它,然后在需要时可查询的任务上隐式调用Load()
。
private List<Task> GetFilteredTasksWithOptionalIncludes(EntityRepository<Task> repo, ITaskRequest model, TaskIncludesModel includes, string accountID)
{
var includedEntities = new List<Expression<Func<Task, object>>>();
includedEntities.Add(t => t.Document.Transaction.Account);
includedEntities.Add(p => p.Signature);
if (includes != null)
{
if (includes.IncludeWorkflowActions)
{
includedEntities.Add(p => p.Actions);
}
if (includes.IncludeFileAttachments)
{
includedEntities.Add(p => p.Attachments);
}
}
IQueryable<Task> tasks = repo.Including(includedEntities.ToArray());
tasks.Load();
return tasks.ToList();
}
或者作为Thewads的后续步骤,只需编写一个很好的旧sproc以一次将所有这些返回多个集合中即可,然后可以使用适当的索引优化数据库架构,并使其尽快运行。
那可能不会流行,但是当您开始谈论数据库性能时,它是一种更快的方法(并且更容易使用,因为您拥有所有用于性能调整的sql工具)...例如,打开查询执行计划。 您可能会发现发疯了。
另一个问题是……您真的需要所有这些数据吗,在加载所有数据之前是否没有可以应用的过滤条件? (假设您解决了多次加载问题)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.