【问题标题】:EF Core 3, optimize lots of Include/ThenIncludeEF Core 3,优化很多 Include/ThenInclude
【发布时间】:2020-08-24 19:19:25
【问题描述】:

我有这样的查询

return await _ctx.Activities
            .Include(a => a.Attributes)
            .Include(a => a.Roles)
            .Include(a => a.Bookmarks)
            .Include(a => a.VideoMetas)
                .ThenInclude(vm => vm.Instances)
            .Include(a => a.ImageMetas)
                .ThenInclude(im => im.Instances)
            .Include(a => a.Procedure)
                .ThenInclude(p => p.Attributes)
            .FirstOrDefaultAsync(a => a.Id == id);

结果非常缓慢。在EF 6 你可以做.Include(v => v.VideoMetas.Select(vm => vm.Instances) 这有点快(我猜,没有看过SQL Profiler 和实际查询tbh)。我该如何优化呢?我也可以使用EF Plus,它有.IncludeOptimized(),但没有.ThenInclude() 的版本。我听说我可以使用.Select 而不是.Include(),但我真的不确定如何在这个查询中处理它。

【问题讨论】:

标签: c# sql-server entity-framework-core


【解决方案1】:

您需要将其拆分为多个查询,以提高性能。 您可以为此使用显式加载。 这不是最漂亮的解决方案,但它有效。希望 EF 5 中会出现更简单的解决方案。

我在猜测哪些字段是集合,哪些是“正常”条目,但类似这样:

var activity = await _ctx.Activities.FindAsync(Id);

await context.Entry(activity)
    .Collection(a => a.Attributes)
    .LoadAsync();

await context.Entry(activity)
    .Collection(a => a.Roles)
    .LoadAsync();

await context.Entry(activity)
    .Collection(a => a.Bookmarks)
    .LoadAsync();

await context.Entry(activity)
    .Collection(a => a.VideoMetas)
    .Query()
    .Include(vm => vm.Instances)
    .LoadAsync();

await context.Entry(activity)
    .Collection(a => a.ImageMetas)
    .Query()
    .Include(im => im.Instances)
    .LoadAsync();

await context.Entry(activity)
    .Reference(a => a.Procedure)
    .Query()
    .Include(p => p.Attributes)
    .LoadAsync();

return activity;

【讨论】:

    【解决方案2】:

    你不能。这是 SQL 与之抗争的维度扩展。 Ef 2.2 有什么可以被视为从这个开始的尝试,但他们没有让它工作并删除它。

    您最好的机会是加载多个(可能是并行的)查询,然后将结果拼接到内存中。对于 EF,有一些库可以做到这一点 - 不确定它们是否适用于 EfCore。他们将查询作为多个查询运行。

    【讨论】:

    • 添加到汤姆的答案。这是 EF Core 3.0 中没有经过深思熟虑的重大更改而没有提供恢复多查询选项的好方法的结果。在他们的 GitHub 问题跟踪器中有几个相关问题,在这里 Significant Query Slowdown When Using Multiple Joins Due To Changes In 3.0 #18022 您可以找到讨论以及 EF Core 团队成员之一提供的荒谬(尤其是对于无跟踪查询)“解决方案”。
    • 但您可以直接使用 Entity Frameworo Plus(谷歌,开源)。它确实添加了很多功能;)包括 IncludeOptimized ,它确实 - 是的,正是这个。这是有趣的事情。一些有能力的开发人员会做 EfCore 开发人员无法完成的工作,甚至更多。
    • 没错!只是我宁愿称其为 SAD 事实 :( 但这似乎是所有较新的 MSFT 堆栈的方向。
    • 是的,但是EF Core Plus 没有.ThenInclude() 的选项
    【解决方案3】:

    此查询运行速度必然会很慢,因为在将其解析为 SQL 时会创建非常复杂的查询,其中所有列都是从所有表中选择的。处理这些查询时优化性能的最佳方法是拆分为多个查询并使用 select 仅选择那些需要的列。

    【讨论】:

      【解决方案4】:

      如果您知道查询结果在一天中可以更改多少次。将查询结果保存在缓存中不是第一次请求,但获得下一次请求的结果会更快。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-21
        • 1970-01-01
        • 2020-02-12
        • 1970-01-01
        • 1970-01-01
        • 2019-01-03
        • 1970-01-01
        相关资源
        最近更新 更多