C# 如何解决实体框架中的慢速连接查询
我有一个MVC4项目,它首先使用EntityFramework6的代码(由SQLServer2008支持)。我正在尝试优化一个特别讨厌的查询,它看起来像:C# 如何解决实体框架中的慢速连接查询,c#,.net,sql,entity-framework,ef-code-first,C#,.net,Sql,Entity Framework,Ef Code First,我有一个MVC4项目,它首先使用EntityFramework6的代码(由SQLServer2008支持)。我正在尝试优化一个特别讨厌的查询,它看起来像: var tops = Context.Top .Include(t => t.Foo .Select(f => f.FooChild1 .Select(c => c.Baz))) .Include(t => t.F
var tops = Context.Top
.Include(t =>
t.Foo
.Select(f => f.FooChild1
.Select(c => c.Baz)))
.Include(t =>
t.Foo
.Select(f => f.FooChild3))
.Include(t =>
t.Foo
.Select(f => f.FooChild2))
.Include(t =>
t.Foo
.Select(f => f.FooChild1
.Select(c => c.Bar)))
.Where(t => t.Foo.Count > 0)
.ToList();
这些关系看起来像:
Top
1 ----> 0..N Foo
1 ----> 0..N FooChild1
1 ----> 0..N Bar
1 ----> 0..N Baz
1 ----> 0..N FooChild2
0..N ----> 1 FooChild3
如您所见,查询进行了大量的即时加载,因此生成的查询具有大量的连接。事实证明,延迟加载对于我处理结果数据的过程来说太慢了
为此生成的查询在我的SQL Server上执行大约需要2秒,但是手动编写的查询只需要大约91毫秒就可以获得所需的数据。我可以做些什么来改进这一点吗
我尝试过的
我试着通过在我需要的所有其他表上调用Load()
并去掉所有Include
来预加载。我不知道为什么(可能这个技巧对DbContext
不起作用),但它没有效果。导航属性被延迟加载
我在考虑什么
Top
表中。我不喜欢在这个选项中重复数据,但至少我不需要遍历这么多导航属性有任何指针吗?您可以使用预编译查询来提高案例中的性能。 比如(例如,因为我不知道你的类型):
static readonly Func s_compiledQuery2=
CompiledQuery.Compile(
(ctx,总计)=>来自ctx.SalesOrderHeaders中的订单
其中order.TotalDue>=总计
选择订单);
静态void CompiledQuery2()
{
使用(AdventureWorksEntities上下文=新建AdventureWorksEntities())
{
十进制总到期日=200.00M;
IQueryable orders=s_compiledQuery2.Invoke(上下文,totalDue);
foreach(订单中的SalesOrderHeader订单)
{
WriteLine(“ID:{0}订单日期:{1}到期总天数:{2}”,
order.SalesOrderID,
order.OrderDate,
订单(全部到期);
}
}
}
感谢您的回复。我不确定编译后的查询是否能帮助我。。。也许你可以详细说明一下?我的理解是,如果您重复进行相同的查询,那么编译后的查询将非常有用。我的问题是生成的查询效率有多低(比手工创建的查询慢20倍),而且我感觉,与在SQL Server上执行查询所需的2秒钟相比,动态查询编译时间微不足道。您对其进行了分析吗?您是否将ef生成的查询与手工生成的查询进行了比较?如果你把它们拿出来比较一下,我可以帮你更准确。
static readonly Func<AdventureWorksEntities, Decimal, IQueryable<SalesOrderHeader>> s_compiledQuery2 =
CompiledQuery.Compile<AdventureWorksEntities, Decimal, IQueryable<SalesOrderHeader>>(
(ctx, total) => from order in ctx.SalesOrderHeaders
where order.TotalDue >= total
select order);
static void CompiledQuery2()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
Decimal totalDue = 200.00M;
IQueryable<SalesOrderHeader> orders = s_compiledQuery2.Invoke(context, totalDue);
foreach (SalesOrderHeader order in orders)
{
Console.WriteLine("ID: {0} Order date: {1} Total due: {2}",
order.SalesOrderID,
order.OrderDate,
order.TotalDue);
}
}
}