实体框架超时

时间:2012-10-07 16:20:01

标签: entity-framework linq-to-sql

我一直试图弄清楚如何在过去几天优化以下查询并且没有太多运气。现在我的测试数据库返回大约300条记录,嵌套数据非常少,但是运行需要4-5秒,而LINQ生成的SQL非常长(这里包含的时间太长)。任何建议都将非常感谢。

总结这个查询,我试图返回一个有点当前状态的客户列表的“快照”。一方包含一个或多个具有角色的客户端(ASPNET角色提供程序),Journal返回Party中所有客户端的最后一个日记帐分录,同样适用于Task和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()

1 个答案:

答案 0 :(得分:0)

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

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

    //am not sure what the exact query would be, and project it using ToList()
    var clients = GetClientsForParty(); 

    var parties = Parties.Include("Journal").Include("Tasks")
          .Where(p=>p.BrokerID == userID).Select( p => { 

    ....
    //then use the in-memory clients
    IsBuyer = clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer")),
    ...
    }
    )

在所有情况下,请安装EF profiler并查看您的查询是如何受到影响的。 EF可以安静令人惊讶。比如在投影之前放置OrderBy,对于所有这些FirstOrDefault或SingleOrDefault来说,它们都会产生很大的影响。

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

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

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

//use your optimized SQL query that you write or even call a stored procedure
db.Database.SQLQuery("select * from .... join .... on");

我正在围绕EF撰写关于这些问题的blog post。这个帖子还没有完成,但总而言之,只要耐心一点,使用其中一些技巧并观察它们的影响(并测量它),你就能达到你想要的效果。