【问题标题】:EF Takes Forever to Generate this QueryEF 永远生成此查询
【发布时间】:2010-08-17 15:48:26
【问题描述】:

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

return (from p in _ctx.Parents  
.Include( "Children" )  
select p).AsQueryable<Parent>();  

然后在过滤器中,我想通过子 ID 列表过滤父级:

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;  

我的 id 列表非常庞大。这会生成一个简单的 SQL 语句,它确实有一个巨大的 id 列表“in (1,2,3...)”,但它自己运行并不需要太多时间。然而,EF 只需要一整分钟来生成语句。我通过设置断点并调用来证明这一点:

((ObjectQuery<Parent>)filtered).ToTraceString();

这需要所有时间。问题出在我最后的 linq 语句中吗?我不知道在(ids)中做相当于 Child.ChildId 的任何其他方法。即使我的 linq 语句很糟糕,这到底怎么会花这么长时间?

【问题讨论】:

  • 发布你的架构和生成的sql,你可能会得到更多帮助。
  • 架构似乎无关紧要,父/子关系也不重要。仅从具有大列表的单个表/实体中进行选择时也会出现同样的问题。
  • 对于遇到问题的其他人;据我所知,EF4 没有解决方案。您必须求助于存储过程。更多信息:social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/…

标签: linq performance entity-framework


【解决方案1】:

不幸的是,在 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)))));

这大大加快了速度,但对于您的目的可能还不够,在这种情况下,您将不得不求助于存储过程。不幸的是,这个特定的用例不适合预期的实体框架行为的“盒子”。如果您的 id 列表可以作为来自同一实体上下文的查询开始,那么实体框架将可以正常工作。

【讨论】:

  • 已投票,但未标记为答案。使用存储过程是答案,但我无法使用损坏的查询解决方案。我将使用损坏的 EF 解决方案...
  • 我鼓励您开始赏金或标记答案。即使您为您的问题编写了自己的基于存储过程的答案,FAQ 也明确指出这是可以接受的。当然,我还要指出,我不仅按要求回答了问题,而且还提供了听起来您打算使用的解决方案。
  • 这可能是您将获得的最佳答案。没有人提出对框架的修复,这就是答案。
【解决方案2】:

用 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)) );

【讨论】:

  • Select(s =&gt; s) 什么都不做。在 Where 之后结束。
  • 这对我的情况没有影响。
  • 您是否在 .NET 4 框架上使用 EF4?我只在 EF 的第一个版本中看到了这个问题。
猜你喜欢
  • 2014-04-11
  • 1970-01-01
  • 2017-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多