Entity Framework Core:如何将 2 个 COUNT 查询合并为一个

Posted

技术标签:

【中文标题】Entity Framework Core:如何将 2 个 COUNT 查询合并为一个【英文标题】:Entity Framework Core: How to combine 2 COUNT queries into one 【发布时间】:2021-12-19 00:31:53 【问题描述】:

我正在努力使用 Entity Framework Core 提高后端性能。这是一个小而简单的例子来说明我想要返回的内容:

var filteredMovies = _dataService
    .Repository
    .Where(movie => movie.Genre == 'Drama')
    .Where(...many other conditions, joins, etc...);

var counts1 = filteredMovies.Count(movie => movie.director == 'Spielberg');
var counts2 = filteredMovies.Count(movie => movie.director == 'Nolan');

return new Summary 

    SpielbergCount = counts1,
    NolanCount = counts2,
;

这将生成 2 个 SQL 查询,每个查询都经过所有 WHERE、JOIN 步骤。 我在 SQL 中看到的是,我可以这样写,只执行 1 个查询:

SELECT
    SUM(CASE WHEN Director = 'Spielberg' THEN 1 ELSE 0 END) SpielbergCount,
    SUM(CASE WHEN Director = 'Nolan' THEN 1 ELSE 0 END) NolanCount
FROM Movies
JOIN ....
WHERE ....

2 个问题:

    如何将最后一个查询转换为 EntityFramework,以防止执行 2 个不同的 SQL 查询? 它会提高性能吗? (即:这是一个小例子,但我有很多查询需要改进,其中一些非常大,大多数查询是相同的,除了一个条件,如本例中的 Director)或者它实际上没有改进有什么?

谢谢

【问题讨论】:

基本上你必须做一个GroupBy,你在一个常数值上分组,这样你就可以在你的Select中做不同的总和。 【参考方案1】:

为了在一个选择中进行多个***聚合,您必须对一个常量值进行分组。

var counts = _dataService
    .Repository
    .Where(movie => movie.Genre == 'Drama')
    .Where(...many other conditions, joins, etc...)
    .GroupBy(x => 1)
    .Select(grp => new Summary 
    
        SpielbergCount = grp.Count(movie => movie.director == 'Spielberg'),
        NolanCount = grp.Count(movie => movie.director == 'Nolan'),
    )
    .Single();

【讨论】:

Hey juharr,您可以在@SupriyoDas 的帖子中看到回复,因为你们俩的解决方案非常相似!谢谢 @NicolasDontigny 请注意,通过对常量值进行分组,结果选择将只有一行,如果需要,您可以执行 Single。就性能而言,它实际上取决于您的表的设置方式,但这会将其减少到一个查询,而不是通常性能更高的 2 个。【参考方案2】:
return _dataService
  .Repository
  .Where(movie => movie.Genre == 'Drama')
  .Where(movie => movie.director == 'Spielberg' || movie.director == 'Nolan')
  .Where(...many other conditions, joins, etc...)
  .GroupBy(movie => movie.director)
  .Select(g => new Summary 
  
      SpielbergCount = g.Count(x => x.director == 'Spielberg'),
      NolanCount = g.Count(x => x.director == 'Nolan'),
  );

1.如何将最后一个查询转换为 EntityFramework,以防止执行 2 个不同的 SQL 查询?

尝试使用 Group By 和 Count with Filter。

2。它会提高性能吗?或者它实际上并没有改善什么?

提高性能的一些技巧

如果不需要,请避免获取所有字段 仅检索所需数量的记录 如果您想将处理从 SQL 服务器转移到应用程序服务器,请尝试使用 AsEnumerable。

【讨论】:

但是与SQL中的SUM相反,根据我的理解,这将返回一个Summary对象的列表,因为GroupBy。 SQL 查询等效项将是 SELECT TOP(1) COUNT(...), COUNT(...) 而不仅仅是 SELECT COUNT(...), COUNT(...) 所以,我将不得不申请 .FirstOrDefault () 在获得 2 个计数之前对该对象进行处理,这似乎不是最佳实践,您怎么看?我什至可以通过应用它来提高性能吗? 这将产生 2 行,其中 Spielberg 行的 SpeilbergCount 和 NolanCount 将为 0,而 Nolan 行的 NolanCount 和 SpeilbergCount 将为 0。这就是您需要分组的原因而是一个常量值。

以上是关于Entity Framework Core:如何将 2 个 COUNT 查询合并为一个的主要内容,如果未能解决你的问题,请参考以下文章

如何将 MySQL 与 .NET Core 3 和 Entity Framework 6 集成

如何将 C# 8.0 可空引用类型与 Entity Framework Core 模型一起使用?

如何使用 Entity Framework Core 正确保存 DateTime?

如何将 Sql 查询转换为 Linq 及其在 Entity Framework Core 中的 Join() 方法的等价物

如何使用 Entity Framework Core 将 SQL 数据从一个表传输到另一个表

使用 Entity Framework Core 将文件存储在数据库中