Sql Ef核心搜索子项,订购父项

Sql Ef核心搜索子项,订购父项,sql,asp.net,entity-framework,asp.net-core,entity-framework-core,Sql,Asp.net,Entity Framework,Asp.net Core,Entity Framework Core,我有两个模型父对象和子对象,我希望检索所有unitid=5且按族排序的不同父对象 public class Parent { public int Id { get; set; } public string Family { get; set; } public List<Child> Children { get; set; } } public class Child { public int Id { get; set; } pub

我有两个模型父对象和子对象,我希望检索所有unitid=5且按族排序的不同父对象

 public class Parent
{
    public int Id { get; set; }
    public string Family { get; set; }
    public List<Child> Children { get; set; }
}

public class Child
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public int UnitId { get; set; }
    public Parent parent { get; set; }
}

一,。使用按id排序时,速度非常快

二,。使用“按家庭顺序”和“跳过”时,速度较慢

三,。族被索引

四,。Ef核心3.1


哪种解决方案正确或更好?

检查以下两个查询的性能:

var父项=
来自Context.Set()中的p
其中p.Children.Any(c=>c.UnitId==5)
orderby p.Family
选择p;
父母
.Take(30)
.Skip(0)
.ToList();
还有一个:

var parentId=
来自Context.Set()中的c
其中c.UnitId==5
选择c.ParentId
变量父项=
来自Context.Set()中的p
p.id等于id的parentId.Distinct()中的join id
orderby p.Family
选择p;
父母
.Take(30)
.Skip(0)
.ToList();

首先,如果您使用
EFCore<3.0
,它有一个奇怪的功能,称为客户端查询自动评估,因此通过查看
输出
窗口,查看是否有关于自动评估的任何警告,确保数据不会无意中全部拉到客户端并在客户端上处理。其次,您可以直接尝试生成的查询,看看是否可以通过编写原始查询来实际优化它。如果不是,则受数据库(而不是LINQ)的限制。在这种情况下,我怀疑
系列
没有索引,在该列上排序将非常慢。尝试在sql server的indexed和EfCore 3.1中为itfamily编制索引,当我编写从子级到父级的左连接时,结果很快。但在EF中,我不能从一个孩子加入到另一个家长。它转换为内部连接在您的查询中有一个
不同的
,恐怕您没有将其包括在左侧连接查询中(可能只是为了测试速度)。如果要区分的组合列位于一个表中,我们可以很容易地在该表上应用索引,但这里它们位于两个表上。我可以看出,这将导致一个相当复杂的查询。如果可能,您应该尝试共享该查询以供其他人查看。
SelectMany
将使用内部联接。要显式使用左连接,您可能必须使用
GroupJoin
。但我们仍然需要弄清楚它是否真的因为内部连接而变慢了。我的意思是在慢速和快速版本之间编写查询时应该是公平的。Distinct用于防止重复父行。是的,当我从父项中删除不同的结果是快速的,但重复的记录。在distinct列中没有索引。这些查询肯定比OP编写的查询逻辑更简单,但是仍然不确定它是否可以执行得更好。让我们等待OP的响应:)我测试了两个查询,但问题没有解决。家族专栏是波斯语的,它对搜索和排序重要吗?最初的问题不是波斯语的排序。但是是的,这是一个问题@DavoodMir这正是我所怀疑的:)实际上,在你的问题中发布的第一个生成的查询很难变得更简单。虽然此答案中的LINQ查询看起来更简单,但生成的查询可能不是:)。顺便说一句,你有没有尝试过我关于索引
Id
系列的建议?从您发布的第一个生成的查询来看,我非常确定它应该会大大提高性能。@SvyatoslavDanyliv您在本文中的回答提高了性能,
var parents= Context.Set<Parent>()
                    .SelectMany(x => x.Children.DefaultIfEmpty(), 
                                (u, r) => new { 
                                          Parent = u, 
                                          Child = r })
                    .Where(x=>x.Child.UnitId == 5)
                    .Select(m => new Parent{ 
                                      Id = m.Parent.Id, 
                                      Family= m.Parent.Family
                                 })
                    .Distinct()
                    .OrderBy(x=>x.Family)
                    .Take(30).Skip(0).ToList();
SELECT [t].[Id], [t].[Family] FROM (
SELECT  distinct [a].[Id],  [a].[Family]
FROM [Parent]  AS [a]
LEFT JOIN [Children] AS [r] ON [a].[Id] = [r].[ParentId]
WHERE  ([r].[unitid] = 5) AS [t] ORDER BY [t].[family] OFFSET 0 ROWS FETCH next 30 ROWS ONLY
var parents = Context.Set<Children>()
                     .Include(x=>x.Parent)
                     .Where(x=>x.UnitId ==5)
                     .Select(m => new Parent{ 
                                      Id = m.ParentId , 
                                      Family = m.Parent.Family})
                     .Distinct()
                     .OrderBy(x=>x.Family)
                     .Take(30).Skip(0).ToList();
SELECT [t0].[Id],[t0].[Family] FROM ( SELECT DISTINCT [t].[Id], [t].[Family]
FROM [Children] AS [r]
INNER JOIN (
    SELECT [a].[Id] , [a].[Family]
    FROM [Parent] AS [a]
) AS [t] ON [r].[ParentId] = [t].[Id]
WHERE ([r].[UnitId] = 5)  AS [t0] ORDER BY [t0].[Family] OFFSET 0 ROWS FETCH next 30 ROWS ONLY