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 查询优化:我可以在 List<string> 上使用 Contains 吗?