EF Where(x => x.ColumnVal == 1)vs FirstOrDefault(x => x.Column == 1)

时间:2010-10-28 21:20:53

标签: entity-framework linq-to-entities

我有一个LINQ查询,可以加载对象的层次结构,如下所示。

查询#1

var result = db.Orders
               .Include("Customer")
               // many other .Include() here
               .FirstOrDefault(x => x.Customer.CustomerId == 1 &&
                                    x.OrderId == orderId);

我有主要表现问题 CPU使用率接近100%,内存使用率非常高。

我将其调整为以下内容并解决了性能问题。

查询#2

var result = db.Orders
               .Include("Customer")
               // many other .Include() here
               .Where(x => x.Customer.CustomerId == 1 &&
                           x.OrderId == orderId)
               .FirstOrDefault();



我只想证实我的怀疑 查询#1可能会遍历我在记忆中的所有记录,寻找匹配的记录
VS
查询#2过滤数据库中的记录,然后仅获取第一条记录。

这就是查询#1 出现性能问题的原因吗?

为了安全起见,我是否需要在.Select(x => x)之前使用.FirstOrDefault()

查询#3

var result = db.Orders
               .Include("Customer")
               // many other .Include() here
               .Where(x => x.Customer.CustomerId == 1 &&
                           x.OrderId == orderId)
               .Select(x => x)
               .FirstOrDefault();

3 个答案:

答案 0 :(得分:3)

不,它们都应该在执行时产生相同的SQL查询。您可以通过查看 SQL Profiler 来证明它,并查看在两种情况下从EF提交的确切SQL是什么。您的性能优化应该是由其他一些因素引起的。原因如下:

包含方法会返回 ObjectQuery<T>

public class ObjectQuery<T> : ObjectQuery, IOrderedQueryable<T>, 
                              IQueryable<T>, IEnumerable<T>, 
                              IOrderedQueryable, IQueryable, 
                              IEnumerable, IListSource

这意味着它的 FirstOrDefault 方法带有2个重载:

// Defined by Enumerable:
FirstOrDefault(Func<T, Boolean>)

// Defined by Queryable:
FirstOrDefault(Expression<Func<T, Boolean>>)

编译.FirstOrDefault(x => x.Customer.CustomerId == 1编译器时,将进入名为 重载决策 的过程,以推断lambda表达式x => x.Customer.CustomerId == 1的类型,因为它是可转换为两种重载参数类型的类型。
编译器将使用一种算法(我仍然试图在C#语言规范中找到它!),弄清楚将lambda转换为Expression<Func<T, Boolean> 更好的转换 而不是Func<T, Boolean>所以选择 IQueryable 重载。
因此,在SQL事件探查器中观察谓词时,您将在生成的SQL中看到谓词。

答案 1 :(得分:0)

我找到了罪魁祸首。这是Entity Framework生成的 SQL查询 我有一个复杂的Schema,有很多多对多的关系。

实体框架正在生成 32,000行 SQL字符串:'(
现在,我正在更改我的代码以手动加载层次结构。

如果有人知道一些关于Eager Loading和多对多关系的好文章,请告诉我。

答案 2 :(得分:0)

我认为最好使用... Where( condition )。Take(1).FirstOrDefault()因为Take(1)可以很容易地作为TOP子句转换为SQL。跟我一个人?