我有一个父子表关系。在存储库中,我这样做:
return (from p in _ctx.Parents
.Include( "Children" )
select p).AsQueryable<Parent>(); 然后在筛选器中,我希望通过子ids列表筛选父ids:
IQueryable<Parent> qry; // from above
List<int> ids; // huge list (8500)
var filtered =
from p in qry.Where( p => p.Children.Any(c => ids.Contains(c.ChildId)) ) select s; 我的is列表很大。这将生成一个简单的SQL语句,该语句确实具有一个巨大的it列表"in (1,2,3...)",但是它本身运行起来并不需要太多时间。然而,EF仅生成语句就需要大约一分钟的时间。我通过设置断点并调用以下命令来证明这一点:
((ObjectQuery<Parent>)filtered).ToTraceString();这需要花费所有的时间。问题出在我上一条linq语句中吗?我不知道还有没有其他方法在(ids)中做等同于Child.ChildId的事情。即使我的linq语句很糟糕,这怎么会花这么长时间呢?
发布于 2010-08-24 08:06:05
不幸的是,在Linq to Entities中构建查询是一个相当沉重的打击,但我发现它通常可以节省时间,因为它能够在实际访问数据库之前从它们的组件构建查询。
很可能他们实现Contains方法的方式使用了一种算法,该算法假设Contains通常用于相对较小的数据集。根据我的测试,列表中每个ID所需的时间在8000左右开始飙升。
因此,将查询分解为多个片段可能会有所帮助。将它们分组到1000个或更少的组中,并连接一组Where表达式。
var idGroups = ids.GroupBy(i => i / 1000);
var q = Parents.Include("Children").AsQueryable();
var newQ = idGroups.Aggregate(q,
(s, g) => s.Concat(
q.Where(w => w.Children.Any(wi => g.Contains(wi.ChildId)))));这大大加快了速度,但可能不足以满足您的需要,在这种情况下,您将不得不求助于存储过程。不幸的是,这个特殊的用例并不符合预期的实体框架行为的“盒子”。如果您的If列表可以作为来自同一实体上下文的查询开始,那么实体框架就会工作得很好。
发布于 2010-08-24 07:14:13
用Lambda语法重写你的查询,它会减少3秒的时间(至少对我的EF项目是这样的)。
return _ctx.Parents.Include( "Children" ).AsQueryable<Parent>(); 和
IQueryable<Parent> qry; // from above
List<int> ids; // huge list (8500)
var filtered = qry.Where( p => p.Children.Any(c => ids.Contains(c.ChildId)) );https://stackoverflow.com/questions/3504339
复制相似问题