1

在过去的几天里,我一直在试图弄清楚如何优化以下查询,但运气不佳。现在我的测试数据库返回大约 300 条记录,嵌套数据很少,但运行需要 4-5 秒,并且 LINQ 生成的 SQL 非常长(太长,无法包含在此处)。任何建议将不胜感激。

总结这个查询,我试图返回一个具有当前状态的客户列表的有点扁平的“快照”。一方包含一个或多个具有角色的客户端(ASPNET 角色提供程序),日志返回一方中所有客户端的最后 1 个日志条目,任务和 LastLoginDate 也是如此,因此 OrderBy 和 FirstOrDefault 函数。

Guid userID = 'some user ID'
var parties = Parties.Where(p => p.BrokerID == userID).Select(p => new
{
ID = p.ID,
Title = p.Title,
Goal = p.Goal,
Groups = p.Groups,
IsBuyer = p.Clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer")),
IsSeller = p.Clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "seller")),
Journal = p.Clients.SelectMany(c => c.Journals).OrderByDescending(j => j.OccuredOn).Select(j=> new 
    { 
        ID = j.ID,
        Title = j.Title,
        OccurredOn = j.OccuredOn,
        SubCatTitle = j.JournalSubcategory.Title
    }).FirstOrDefault(),
LastLoginDate = p.Clients.OrderByDescending(c=>c.LastLoginDate).Select(c=>c.LastLoginDate).FirstOrDefault(),
MarketingPlanCount = p.Clients.SelectMany(c => c.MarketingPlans).Count(),
Task = p.Tasks.Where(t=>t.DueDate != null && t.DueDate > DateTime.Now).OrderBy(t=>t.DueDate).Select(t=> new 
    {
        ID = t.TaskID,
        DueDate = t.DueDate,
        Title = t.Title
    }).FirstOrDefault(),
Clients = p.Clients.Select(c => new
    {
        ID = c.ID,
        FirstName = c.FirstName,
        MiddleName = c.MiddleName,
        LastName = c.LastName,
        Email = c.Email,
        LastLogin = c.LastLoginDate
    })
}).OrderBy(p => p.Title).ToList()
4

1 回答 1

0

我认为发布 SQL 可以为我们提供一些线索,因为在投影之前或之后出现 OrderBy 的顺序之类的小事情可能会产生很大的不同。

但无论如何,尝试在单独的查询中提取客户端,这可能会简化您的查询。然后在投影之前包括其他表,如 Journal 和 Tasks,看看这对您的查询有何影响:

    //不确定确切的查询是什么,并使用 ToList() 进行投影
    var clients = GetClientsForParty();

    varparty =partys.Include("Journal").Include("Tasks")
          .Where(p=>p.BrokerID == userID).Select(p => {

    ……
    //然后使用内存中的客户端
    IsBuyer = clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer")),
    ...
    }
    )

在所有情况下,安装EF 分析器并查看您的查询是如何受到影响的。英孚可以安静地令人惊讶。就像把 OrderBy 放在投影之前一样,所有这些 FirstOrDefault 或 SingleOrDefault 都一样,它们都可以产生很大的影响。

回到基础,如果你在 LoweredRoleName 上搜索,那么确保它被索引以便查询快速(即使这可能是无用的,因为 EF 可能最终没有使用覆盖索引,因为它正在查询所以许多其他列)。

此外,由于这是查看数据的查询(您不会更改数据),因此请不要忘记关闭实体跟踪,这也会给您带来一些性能提升。

最后,不要忘记你总是可以直接编写你的 SQL 查询并投影到你的 ViewModel 而不是匿名类型(无论如何我认为这是一个很好的做法),所以创建一个名为 PartyViewModel 的类,其中包含你所追求的扁平化视图,并将其与您手工制作的 SQL 一起使用

//使用您编写的优化 SQL 查询,甚至调用存储过程
db.Database.SQLQuery("select * from .... join .... on");

我正在写一篇关于 EF 的这些问题的博文。这篇文章还没有完成,但总而言之,只要耐心等待,使用其中一些技巧并观察它们的效果(并衡量它),你就会达到你想要的。

于 2012-10-07T18:28:18.213 回答