在子查询中包含计数的高效查询

本文关键字:查询 高效 包含计 | 更新日期: 2023-09-27 18:00:25

假设我有一个假设的多对多关系:

public class Paper
{
  public int Id { get; set; }
  public string Title { get; set; }
  public virtual ICollection<Author> Authors { get; set; }
}
public class Author
{
  public int Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<Paper> Papers { get; set; }
}

我想使用LINQ构建一个查询,该查询将显示每个作者与其他作者相比的"受欢迎程度",即作者贡献的论文数量除以所有论文的作者贡献总数。我提出了几个问题来实现这一点。

选项1:

var query1 = from author in db.Authors
             let sum = (double)db.Authors.Sum(a => a.Papers.Count)
             select new
             {
               Author = author,
               Popularity = author.Papers.Count / sum
             };

选项2:

var temp = db.Authors.Select(a => new
           {
             Auth = a,
             Contribs = a.Papers.Count
           });
var query2 = temp.Select(a => new
             {
               Author = a,
               Popularity = a.Contribs / (double)temp.Sum(a2 => a2.Contribs)
             });

基本上,我的问题是:其中哪一个更高效,还有其他单一查询更高效吗?其中任何一个与两个单独的查询相比如何,如以下所示:

double sum = db.Authors.Sum(a => a.Papers.Count);
var query3 = from author in db.Authors
             select new
             {
               Author = author,
               Popularity = author.Papers.Count / sum
             };

在子查询中包含计数的高效查询

首先,您可以自己尝试,看看哪一个耗时最长。

你应该寻找的第一件事是,它们完美地转换成SQL或尽可能接近SQL,这样数据就不会全部加载到内存中,只是为了应用这些计算。

但我觉得选项2可能是你最好的选择,再进行一次优化,以缓存贡献的页面总数。这样,你只需要对数据库进行一次调用,就可以获得你所需要的作者,其余的都将在你的代码中运行,你可以在那里进行并行处理,并做任何你需要的事情来加快速度。

所以这样的东西(对不起,我更喜欢林克流利的写作风格):

//here you can even load only the needed info if you don't need the whole entity.
//I imagine you might only need the name and the Pages.Count which you can use below, this would be another optimization.
var allAuthors = db.Authors.All(); 
var totalPageCount = allAuthors.Sum(x => x.Pages.Count);
var theEndResult = allAuthors .Select(a => new
         {
           Author = a,
           Popularity = a.Pages.Count/ (double)totalPageCount
         });

选项1和选项2应该生成相同的SQL代码。为了可读性,我会选择选项1
选项3将生成两个SQL语句,并且速度稍慢。