使用相关实体优化linq查询

本文关键字:优化 linq 查询 实体 | 更新日期: 2023-09-27 18:27:00

我是linq的新手,我开始写这个查询:

        var dProjects = Projects
         .Select(p => new Models.Project {
            ProjectID = p.ProjectID,
            Status = p.Status,
            ExpiresOn = p.ExpiresOn,
            LatestComments = p.ProjectComments
                               .OrderByDescending(pc => pc.CreatedOn)
                               .Select(pc => pc.Comments)
                               .FirstOrDefault(),                 
            ProjectFileIDs = p.ProjectFiles
                               .Select(pf => pf.BinaryFileID)
                               .AsQueryable()
         })
        .AsQueryable<Models.Project>();

我已经知道这个查询的执行速度会非常慢,因为像ProjectCommentsProjectFiles这样的相关实体会创建嵌套的选择,尽管它可以工作,并为我提供所需的正确结果。

如何优化此查询并获得相同的结果?我的猜测之一是使用inner join,但ProjectCommentsProjectFiles在数据库中已经通过键建立了关系,所以不确定通过再次设置关系可以实现什么。

基本上,从性能的角度来看,需要知道哪种方法是最好的。需要注意的一点是,我正在对ProjectComments进行排序,并且只取最近的一个。我应该使用joingroup by into的组合吗?我们将不胜感激。谢谢

更新:

很抱歉,如果我对我要做的事情不够清楚的话。基本上,在前端,我有一个网格,它显示了带有最新项目注释的项目列表和与项目相关的所有文件列表,这样用户就可以点击这些链接并实际打开这些文档。因此,我上面的查询正在工作,它确实在网格中显示了以下内容:

项目ID(来自项目表)状态(来自项目表)ExpiresOn(来自项目表)LatestComments(ProjectComments表中项目ID为外键的最新条目)ProjectFileID(ProjectFiles表中的文件ID列表,该表将项目ID作为外键-我正在使用这些文件ID并创建链接,以便用户可以打开这些文件)。

所以一切都正常,我已经设置好了,但查询速度有点慢。现在我们的数据很少(只有测试数据),但一旦启动,我预计会有很多用户/数据,因此我想在这个查询上线之前将其优化到最佳状态。所以,这里的目标是基本优化。我确信这不是最好的方法,因为这将创建嵌套的选择。

使用相关实体优化linq查询

在实体框架中,通过将对象返回为对象图而不是投影,可以显著提高查询的性能。实体框架在优化除最复杂的SQL查询之外的所有查询方面都非常有效;热切的";负载与";懒惰;正在加载(在实际访问相关项目之前,不会从数据库中加载这些项目)。此MSDN参考资料是一个很好的起点。

就您的特定查询而言,您可以使用以下技术:

var dbProjects = yourContext.Projects
                    .Include(p => p.ProjectComments
                              .OrderByDescending(pc => pc.CreatedOn)
                              .Select(pc => pc.Comments)
                              .FirstOrDefault()
                            )
                    .Include(p => p.ProjectFileIDs)
                    .AsQueryable<Models.Project>();

请注意,.Include()用于暗示热切加载。

来自MDSN关于加载相关对象的参考,

性能注意事项

当您选择加载相关实体的模式时,请考虑每种方法的行为,即与数据源连接的数量和时间、返回的数据量以及使用单个查询的复杂性。热切加载在单个查询中返回所有相关的实体以及被查询的实体。这意味着,虽然只有一个到数据源的连接,但在初始查询中会返回大量数据。此外,查询路径会导致更复杂的查询,因为在针对数据源执行的查询中需要额外的联接。

显式和延迟加载使您能够推迟对相关对象数据的请求,直到实际需要该数据为止。这产生了一个不那么复杂的初始查询,返回的总数据更少。但是,相关对象的每次连续加载都会连接到数据源并执行查询。在延迟加载的情况下,每当访问导航属性并且尚未加载相关实体时,就会发生这种连接。

如果在Select之前添加Include语句,性能会得到任何提升吗?

示例:

var dProjects = Projects
    .Include(p => p.ProjectComments)
    .Include(p => p.ProjectFiles)

Include允许所有匹配的ProjectComments和ProjectFiles被急切地加载。有关详细信息,请参见加载相关实体。