【问题标题】:Ef core search on child , order on parentEf core search on child , order on parent
【发布时间】:2021-05-14 22:43:12
【问题描述】:

我有两个模型 Parent 和 Child,我想检索所有具有 unitid = 5 并按家庭排序的 Distinct parent

 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; }
}

父表有 500000 条记录,子表有 2000000 条记录。我使用 SelectMany And Distinct 但检索记录需要 8 秒

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

1 .当使用按 id 排序时,速度非常快

2 。用家人点单拿的时候,跳过很慢

3 .家庭被索引

4 . Ef Core 3.1

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

【问题讨论】:

  • 首先如果你使用EFCore &lt; 3.0,它有一个奇怪的特性叫做客户端查询自动评估,所以要确保数据通过查看Output 窗口以查看是否有关于该自动评估的任何警告,不会无意中将所有内容拉到客户端并在客户端上进行处理。其次,您可以直接尝试生成的查询,看看您是否真的可以通过编写原始查询来优化它。如果不是,那么它受您的数据库(而不是 LINQ)的限制。在这种情况下,我怀疑Family 没有被索引,对该列的排序将非常慢。尝试索引它
  • 索引和 EfCore 3.1 中的系列,在我写从子到父结果的左连接时,在 sql server 中很快。但在 EF 中,我不能离开 join from child to parent 。它转化为内部连接
  • 您的查询中有一个Distinct,恐怕您的左连接查询中没有包含它(可能只是为了测试速度)。如果要区分的复合列在一个表中,我们可以轻松地对其应用索引,但这里它们在 2 个表上。我可以看到它会导致一个相当复杂的查询。如果可能,您应该尝试共享该查询以供其他人查看。
  • SelectMany 将使用内部连接。要显式使用左连接,您可能必须使用GroupJoin。但是我们仍然需要确定它是否真的被内部连接减慢了。我的意思是在慢版本和快版本之间编写查询时应该是公平的。
  • Distinct 用于防止重复父行。是的,当我删除不同的结果时,结果是快速但来自父级的重复记录。不同列中没有索引。

标签: sql asp.net entity-framework asp.net-core entity-framework-core


【解决方案1】:

检查这两个查询的性能:

var parents = 
    from p in Context.Set<Parent>()
    where p.Children.Any(c => c.UnitId == 5)
    orderby p.Family
    select p;

parents = parents
    .Take(30)
    .Skip(0)
    .ToList();

还有一个:

var parentIds = 
    from c in Context.Set<Child>()
    where c.UnitId == 5
    select c.ParentId

var parents = 
    from p in Context.Set<Parent>()
    join id in parentIds.Distinct() on p.Id equals id
    orderby p.Family
    select p;

parents = parents
    .Take(30)
    .Skip(0)
    .ToList();

【讨论】:

  • 这些查询肯定比 OP 编写的查询逻辑更简单,但它是否能表现得更好仍然不确定。让我们等待OP的回应:)
  • 我测试了两个查询但问题没有解决。家庭专栏是波斯语的,搜索和排序重要吗?
  • 最初的问题不是关于波斯语的订购。但是,是的,这是一个问题。 docs.microsoft.com/en-us/ef/core/miscellaneous/…
  • @DavoodMir 这就是我所怀疑的 :) 确实,在您的问题中发布的第一个生成的查询很难变得更简单。尽管此答案中的 LINQ 查询看起来更简单,但生成的查询可能不会:)。顺便说一句,您是否尝试过我关于索引 IdFamily 对的建议?从您发布的第一个生成查询开始,我很确定它应该会大大提高性能。
  • @SvyatoslavDanyliv 你在这篇文章中的回答提高了性能,stackoverflow.com/a/66152338/3332302
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 2013-01-20
相关资源
最近更新 更多