使用GROUP BY和COUNT优化/重写LINQ查询

Snæ*_*ørn 5 c# linq

我正在尝试按以下数据集计算按名称分组的唯一Foos和Bars.

Id  |   IsActive    |   Name    |   Foo     |   Bar
1   |       1       |   A       |   11      |   null
2   |       1       |   A       |   11      |   null
3   |       1       |   A       |   null    |   123
4   |       1       |   B       |   null    |   321
Run Code Online (Sandbox Code Playgroud)

我希望上面数据的结果是:

Expected:
A = 2;
B = 1;
Run Code Online (Sandbox Code Playgroud)

我尝试按名称,Foo,Bar进行分组,然后再按名称分组,并使用计数来获取"行"计数.但那并没有给我正确的结果.(或者ToDictionary扔了一个重复的键,我玩了很多,所以不记得了)

db.MyEntity
    .Where(x => x.IsActive)
    .GroupBy(x => new { x.Name, x.Foo, x.Bar })
    .GroupBy(x => new { x.Key.Name, Count = x.Count() })
    .ToDictionary(x => x.Key, x => x.Count);
Run Code Online (Sandbox Code Playgroud)

所以我提出了这个LINQ查询.但它相当慢.

db.MyEntity
    .Where(x => x.IsActive)
    .GroupBy(x => x.Name)
    .ToDictionary(x => x.Key,
        x =>
            x.Where(y => y.Foo != null).Select(y => y.Foo).Distinct().Count() +
            x.Where(y => y.Bar != null).Select(y => y.Bar).Distinct().Count());
Run Code Online (Sandbox Code Playgroud)

我该如何优化它?

这是推荐的实体

public class MyEntity
{
    public int Id { get; set; }
    public bool IsActive { get; set; }
    public string Name { get; set; }
    public int? Foo { get; set; }
    public int? Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

编辑

我也试过这个查询

db.MyEntity
    .Where(x => x.IsActive)
    .GroupBy(x => new { x.Name, x.Foo, x.Bar })
    .GroupBy(x => x.Key.Name)
    .ToDictionary(x => x.Key, x => x.Count());
Run Code Online (Sandbox Code Playgroud)

但那引发了超时异常:(

Ser*_*rvy 5

该查询效率极低,因为您在客户端完成大部分工作(构建字典所涉及的所有工作),而无法使用数据库进行投影。这是一个问题,因为数据库(特别是如果这些值被索引)可以比客户端更快地完成这项工作,而且还因为在数据库上进行投影涉及通过网络发送的数据少得多。

因此,只需在对数据进行分组之前进行预测即可。

var activeItems = db.MyEntity.Where(x => x.IsActive);

var query = activeItems.Select(x => new { Name, Value = x.Foo}).Distinct()
    .Concat(activeItems.Select(x => new { Name, Value = x.Bar}).Distinct())        
    .Where(x => x != null)
    .GroupBy(pair => pair.Name)
    .Select(group => new { group.Key, Count = Group.Count()})
    .ToDictionary(pair => pair.Key, pair => pair.Count);
Run Code Online (Sandbox Code Playgroud)