Linq to entites (EF6) return 每个组的最新记录使用 T-SQL 服务器中的行号

Linq to entites (EF6) return latest records of each group using Row number in T-SQL server

我正在使用 Linq to entities 获取每个组的最新更新记录。但实际上当我检查 sql 探查器时,我的 Ling 查询生成了许多子查询,因此完成它真的需要太多时间。为了解决这个性能问题,我已经编写了下面提到的本机 T-Sql,因此我正在寻找使用 Linq 查询的解决方案,entity framework 使用 ( ROW_NUMBER() OVER(PARTITION BY ...) 以下是我的示例数据:

TSQL 查询:

WITH summary AS (
SELECT  a.ParentId 
       ,a.Name
       ,a.Email
       ,p.Created 
       ,p.[Status], 
       ROW_NUMBER() OVER(PARTITION BY p.ParentId
                             ORDER BY p.Created DESC) AS rk
  FROM Parent a
    LEFT JOIN Child p
        ON a.ParentId = P.ParentId
    )
SELECT s.*
FROM summary s
WHERE s.rk = 1

我使用 Linq 的示例 C#:

using (DbContext context = new DbContext())
{
  return context.Parents.Where(p => p.ParentId == parentId)
                .Include(a => a.Childs)
                .Select(x => new ObjectDto()
                {
                  ParentId = x.ParentId,
                  Status = x.Childs.OrderByDescending(a => a.Created).FirstOrDefault(p => p.ParentId).Status,
                  ChildName = x.Childs.OrderByDescending(a => a.Created).FirstOrDefault(p => p.ParentId).ChildName
                })
                .ToList();
}

有几件事可以改进您的 C# 查询:

using (DbContext context = new DbContext())
{
    return context.Parents.Where(p => p.ParentId == parentId)
                .Include(a => a.Childs)
                .Select(x => new ObjectDto()
                {
                  ParentId = x.ParentId,
                  Status = x.Childs.OrderByDescending(a => a.Created).FirstOrDefault(p => p.ParentId).Status,
                  ChildName = x.Childs.OrderByDescending(a => a.ChildName).FirstOrDefault(p => p.ParentId).ChildName
                })
               .ToList();
}

首先,Include 调用在这里什么都不做,因为您不只是返回 EF 实体(因此延迟加载语义不适用)。

其次:避免使用let子句的重复子查询。

(传递给 FirstOrDefault 的 lambda 一定是一个错误,因为它需要一个 Func<T, bool> 而不是。)

因此

using (DbContext context = new DbContext()) {
    return await (from p in context.Parents
                  where p.ParentId == parentId
                  let cs = p.Childs.OrderByDescending(a => a.Created).FirstOrDefault()
                  select new ObjectDto {
                       ParentId = p.ParentId,
                       Status = cs.Status,
                       ChildName = cs.ChildName                      
                  }).ToListAsync();
}

不然看起来还算合理。您需要查看生成的查询计划,看看您可以在索引方面做些什么。

如果这不起作用,则使用您可以完全控制的存储过程。 (机械生成代码——无需在代码生成器和优化器中做大量工作——总是可以被手写代码打败)。