Sql Ef核心搜索子项,订购父项
我有两个模型父对象和子对象,我希望检索所有unitid=5且按族排序的不同父对象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
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