我有一个linq查询,它根据页面命中表返回用户查看的最后一页。这些字段只是TimeStamp
,UserID
和URL
,它们是从用户活动中记录的。查询如下所示:
public static IQueryable GetUserStatus()
{
var ctx = new AppEntities();
var currentPageHits = ctx.Pagehits
.GroupBy(x => x.UserID)
.Select(x => x.Where(y => y.TimeStamp == x.Max(z => z.TimeStamp)))
.SelectMany(x => x);
return currentPageHits.OrderByDescending(o => o.TimeStamp);
}
查询工作正常,但运行缓慢。我们的DBA向我们保证,该表在所有正确的位置都有索引,并且问题必须在查询中。
是否存在任何内在错误或有不良之处,或者是否有更有效的方法来获得相同的结果?
答案 0 :(得分:3)
你可以尝试:
var currentPageHits2 = ctx.Pagehits
.GroupBy(x => x.UserID)
.Select(x => x.OrderByDescending(y => y.TimeStamp).First())
.OrderByDescending(x => x.TimeStamp);
但速度应该是一样的。
请注意,此查询与您的查询之间存在细微差别...如果 UserId 有两个" max TimeStamp " PageHits 使用相同的 TimeStamp ,两行"行"将被退回,只有一个将被退回。
答案 1 :(得分:2)
所以你试着用LINQ实现DENSE_RANK() OVER (PARTITION BY UserID ORDER BY TimeStamp DESC)
?因此,根据Timestamp
,每个用户组的所有最新记录。你可以尝试:
public static IQueryable GetUserStatus()
{
var ctx = new AppEntities();
var currentPageHits = ctx.Pagehits
.GroupBy(x => x.UserID)
.SelectMany(x => x.GroupBy(y => y.TimeStamp).OrderByDescending(g=> g.Key).FirstOrDefault())
.OrderByDescending(x => x.TimeStamp);
return currentPageHits;
}
因此,它按用TimeStamp
对用户组进行分组,然后它采用最新的组(如果是关系,则为一个或多个记录)。 SelectMany
将goups压平为记录。我认为这比你的查询更有效。