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)
不,它们在执行时都应该产生相同的 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>
| 归档时间: |
|
| 查看次数: |
8859 次 |
| 最近记录: |