EF Core 标头-详细信息查询优化

Posted

技术标签:

【中文标题】EF Core 标头-详细信息查询优化【英文标题】:EF Core header-detail query optimization 【发布时间】:2021-12-12 21:52:36 【问题描述】:

我的 SQL Server 数据库中有一个标题-详细信息关系。我有大约 10k 个标头,每个标头都有 1-1k 个详细信息。并且唯一元素的数量约为 1k。

Elements [id]
1
2
3

Headers [id]
1
2
3

Details [id, header_id, element_id]
1 1 1
2 1 2
3 1 3
4 2 1
5 3 1

用这种结构查询标题列表及其详细信息非常容易:

var searchHeaderIds = new List<int>1,2,3;
var headers = context.Headers
                     .Where(h => searchHeaderIds.Contains(h.Id))
                     .Include(h => h.Details)
                     .ToList();

但我要查询的是一个元素列表(1-200),其中每个元素都有一个它所属的标题列表(类似于反转)。我可以用 C# 编写如下:

var searchElementIds = new List<int>1,2,3;
var headers = context.Details
                     .Where(d => searchElementIds.Contains(d.element_id))
                     .GroupBy(d => d.element_id)
                     .Select(g => new  
                                       id = g.Key, 
                                       header_ids = g.Select(x => x.header_id) )
                     .ToList();

但我想知道,使用 SQL/EF 的强大功能最快的方法是什么?

UPD:我已准备好使用额外的数据结构,预处理数据库中的数据,或做任何其他事情来提高性能。

【问题讨论】:

使用Join 而不是Include ***.com/questions/33523974/… 【参考方案1】:

怎么样:

var searchElementIds = new List<int>1,2,3;
var headers = (
    from header in context.Headers
    join detail in context.Details on header.id equals detail.header_id
    where searchElementIds.Contains(detail.element_id)
    select header).Distinct();

如果您想要 Element 类的实例:

var headers = 
    context.Details
        .Where(d => searchElementIds.Contains(d.element_id))
        .GroupBy(d => d.element_id)
        .Select(g => new Element 
                      
                         id = g.Key, 
                         header_ids = g.Select(x => x.header_id
                     )
        .ToList();

不要在查询过程中调用ToList()

【讨论】:

EF 不支持 GroupBy,而且我认为它不能翻译内部 Select。 @scor4er,EF Core 6 应该支持此查询,但肯定不是最佳方式,因为 SQL 标准不允许选择它。 @ArturoMartinez 你是对的,它支持 GroupBy 但在有限的情况下,它不支持组元素的列表,当你尝试这样做时它只会抛出一个错误。看来我必须把它安排在 C# 方面。【参考方案2】:

在您的情况下,这是最优化的查询。它更接近原始帖子,但减少了中间结果的检索字段数:

var headers = context.Details
    .Where(d => searchElementIds.Contains(d.element_id))
    .Select(d => new  d.element_id, d.header_id )
    .ToList() // we need this, EF do not support retrieving grouping detals
    .GroupBy(d => d.element_id)
    .Select(g => new Element
     
        id = g.Key, 
        header_ids = g.Select(x => x.header_id).ToList()
    )
    .ToList();

【讨论】:

以上是关于EF Core 标头-详细信息查询优化的主要内容,如果未能解决你的问题,请参考以下文章

如何优化查询 - Ef core

针对特定 EF Core 查询优化 UNKNOWN

EF Core 查询优化:我可以在 List<string> 上使用 Contains 吗?

#yyds干货盘点#愚公系列2023年02月 .NET/C#知识点-EF Core性能优化之显示编译

Entity Framework Core 性能优化

Entity Framework Core 性能优化