C# 如何解决实体框架中的慢速连接查询

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

我有一个MVC4项目,它首先使用EntityFramework6的代码(由SQLServer2008支持)。我正在尝试优化一个特别讨厌的查询,它看起来像:

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
不起作用),但它没有效果。导航属性被延迟加载

我在考虑什么

  • 我想到的一个选择是手工编写一个查询所需数据的SQL视图,并首先在代码中将实体映射到它。我不知道如何准确地做到这一点,但我希望通过这样做,我可以避免在生成的查询中出现糟糕的性能

  • 修改数据库的设计,以便将所需信息缓存在
    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);
            }
        }            
    }