首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >EF使用Forever来生成此查询

EF使用Forever来生成此查询
EN

Stack Overflow用户
提问于 2010-08-17 23:48:27
回答 2查看 302关注 0票数 10

我有一个父子表关系。在存储库中,我这样做:

代码语言:javascript
复制
return (from p in _ctx.Parents  
.Include( "Children" )  
select p).AsQueryable<Parent>();  

然后在筛选器中,我希望通过子ids列表筛选父ids:

代码语言:javascript
复制
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仅生成语句就需要大约一分钟的时间。我通过设置断点并调用以下命令来证明这一点:

代码语言:javascript
复制
((ObjectQuery<Parent>)filtered).ToTraceString();

这需要花费所有的时间。问题出在我上一条linq语句中吗?我不知道还有没有其他方法在(ids)中做等同于Child.ChildId的事情。即使我的linq语句很糟糕,这怎么会花这么长时间呢?

EN

回答 2

Stack Overflow用户

发布于 2010-08-24 08:06:05

不幸的是,在Linq to Entities中构建查询是一个相当沉重的打击,但我发现它通常可以节省时间,因为它能够在实际访问数据库之前从它们的组件构建查询。

很可能他们实现Contains方法的方式使用了一种算法,该算法假设Contains通常用于相对较小的数据集。根据我的测试,列表中每个ID所需的时间在8000左右开始飙升。

因此,将查询分解为多个片段可能会有所帮助。将它们分组到1000个或更少的组中,并连接一组Where表达式。

代码语言:javascript
复制
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列表可以作为来自同一实体上下文的查询开始,那么实体框架就会工作得很好。

票数 4
EN

Stack Overflow用户

发布于 2010-08-24 07:14:13

用Lambda语法重写你的查询,它会减少3秒的时间(至少对我的EF项目是这样的)。

代码语言:javascript
复制
return _ctx.Parents.Include( "Children" ).AsQueryable<Parent>();  

代码语言:javascript
复制
IQueryable<Parent> qry;  // from above
List<int> ids;  // huge list (8500)
var filtered = qry.Where( p => p.Children.Any(c => ids.Contains(c.ChildId)) );
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3504339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档