我有一个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();
答案 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。跟我一个人?