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

stu*_*tun 6 linq-to-entities entity-framework

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

查询#1

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

我遇到了MAJOR性能问题.
CPU使用率接近100%,内存使用率非常高.

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

查询#2

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



我只想证实我的怀疑.
查询#1可能循环遍历内存中的所有记录,查找匹配的记录,

查询#2过滤数据库中的记录,然后仅获取第一条记录.

这就是Query#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();
Run Code Online (Sandbox Code Playgroud)

Mor*_*avi 4

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

Include方法返回一个ObjectQuery<T>

public class ObjectQuery<T> : ObjectQuery, IOrderedQueryable<T>, 
                              IQueryable<T>, IEnumerable<T>, 
                              IOrderedQueryable, IQueryable, 
                              IEnumerable, IListSource
Run Code Online (Sandbox Code Playgroud)

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

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

// Defined by Queryable:
FirstOrDefault(Expression<Func<T, Boolean>>)
Run Code Online (Sandbox Code Playgroud)

当您编写代码时,.FirstOrDefault(x => x.Customer.CustomerId == 1编译器将进入一个名为“重载解析”的过程来推断 lambda 表达式的类型x => x.Customer.CustomerId == 1,因为它可以转换为两个重载参数类型的类型。
编译器将使用一种算法(我仍在尝试在 C# 语言规范中找到该算法!),发现将 lambda 转换为选择IQueryable重载Expression<Func<T, Boolean>更好。 因此,在 SQL 事件探查器中观察生成的 SQL 时,您将看到该谓词。Func<T, Boolean>