【问题标题】:Efficient query involving count in subquery子查询中涉及计数的高效查询
【发布时间】:2013-02-21 07:41:38
【问题描述】:

假设我有这种假设的多对多关系:

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 的查询计划 - 您将处于一个更好的位置。
  • 您还有一个选择:加入分组并按组计算论文。正如 Jon Skeet 所说,要选择最好的方式来分析输出 sql。

标签: c# linq entity-framework-5


【解决方案1】:

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

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

但我觉得选项 2 可能是您最好的选择,还有一项优化可以缓存贡献的页面总数。这样,您只需调用 db 即可获取您无论如何需要的作者,其余的将在您的代码中运行,您可以并行化并执行任何您需要的操作以使其快速。

所以是这样的(抱歉,我更喜欢 Fluent 的 Linq 写法):

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

【讨论】:

    【解决方案2】:

    选项 1 和 2 应该生成相同的 SQL 代码。为了便于阅读,我会选择选项 1
    选项 3 会生成两条 SQL 语句,速度会慢一些。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      相关资源
      最近更新 更多