简体   繁体   English

如何解决实体框架中的缓慢联接查询

[英]How to work around slow joining queries in Entity Framework

I have an MVC 4 project that is using Code First with Entity Framework 6 (backed by SQL Server 2008). 我有一个MVC 4项目,该项目正在使用Code First和Entity Framework 6(由SQL Server 2008支持)。 I'm trying to optimize a particularly nasty query that looks something like: 我正在尝试优化一个看起来像这样的特别讨厌的查询:

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();

Where the relationships look like: 关系如下所示:

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

As you can see, the query does a lot of eager loading, so the resulting query has a lot of joins. 如您所见,该查询需要大量的加载,因此生成的查询具有大量的联接。 Lazy loading has proved much too slow for what I'm doing with the resulting data. 事实证明,对于我正在处理的结果数据,延迟加载太慢了。

The generated query for this takes about 2 seconds to execute on my SQL Server, but a hand written query that obtains the data I need only takes about 91 ms. 在SQL Server上执行此查询所生成的查询大约需要2秒钟,但是获取我需要的数据的手写查询仅需要大约91毫秒。 Is there anything I can do to improve this? 有什么我可以做来改善的吗?

What I have tried 我尝试过的

I tried pre-loading by calling Load() on all of the other tables that I need and getting rid of all the Include 's. 我尝试通过在需要的所有其他表上调用Load()并摆脱所有Include的方法来进行预加载。 I'm not sure why (maybe this trick does not work with DbContext ), but it had no effect. 我不确定为什么(也许这个技巧不适用于DbContext ),但是没有效果。 Navigation properties were lazy loaded. 导航属性是延迟加载的。

What I am considering 我在考虑什么

  1. One option that occurs to me would be to hand write a SQL view that queries the data I need, and map an entity to it in Code First. 我想到的一个选择是手写一个查询所需数据的SQL视图,并在Code First中将一个实体映射到该视图。 Not sure how to do that exactly, but I hope that by doing that I could avoid the bad performance in the generated query. 不知道如何确切地做到这一点,但是我希望这样做可以避免所生成查询中的不良性能。

  2. Modifying the design of my database so the information I need is cached in the Top table. 修改数据库的设计,以便将我需要的信息缓存在Top表中。 I don't like the duplication of data in this option, but at least I wouldn't have to traverse so many navigation properties. 我不喜欢此选项中的数据重复,但是至少我不必遍历那么多的导航属性。

Any pointers? 有指针吗?

You can use precompiled query to improve performance in your case. 您可以使用预编译查询来提高性能。 Something like (example from msdn cause I don't know your types): 诸如此类(来自msdn的示例,原因是我不知道您的类型):

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);
        }
    }            
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM