1

我有一个 MVC 4 项目,它使用 Code First 和 Entity Framework 6(由 SQL Server 2008 支持)。我正在尝试优化一个特别讨厌的查询,它看起来像:

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's来进行预加载。我不知道为什么(也许这个技巧不适用于DbContext),但它没有效果。导航属性被延迟加载。

我在考虑什么

  1. 我想到的一个选择是手写一个 SQL 视图来查询我需要的数据,并在 Code First 中将一个实体映射到它。不知道如何准确地做到这一点,但我希望这样做可以避免生成的查询中的不良性能。

  2. 修改我的数据库的设计,以便将我需要的信息缓存在Top表中。我不喜欢这个选项中的数据重复,但至少我不必遍历这么多导航属性。

任何指针?

4

1 回答 1

0

您可以使用预编译查询来提高您的情况下的性能。类似的东西(来自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);
        }
    }            
}
于 2013-06-07T18:29:06.370 回答