如何最好地优化这一小部分c#Linq代码

时间:2012-01-10 01:28:10

标签: c# asp.net performance linq optimization

如果你看一下我们的街机主页:

http://www.scirra.com/arcade

在右上角有一个方框,显示最后一个玩这个游戏的人。在我正在使用的分析器中,它显示为运行900毫秒,大约占总页面加载时间的80%。

查询相对简单:

// Recent players
using (MainContext db = new MainContext())
{
    var q = (from c in db.tblArcadeGamePlays
                join a in db.tblProfiles on c.UserID equals a.UserID
                where c.UserID != 0
                select new
                {
                    c.UserID,
                    c.tblForumAuthor.Username,
                    a.EmailAddress,
                    Date = (from d in db.tblArcadeGamePlays where d.UserID == c.UserID orderby d.Date descending select new { d.Date }).Take(1).Single().Date
                })
    .Distinct()
    .OrderByDescending(c => c.Date)
    .Take(16);

但这对我的需求来说太慢了。

这个输出缓存不合适,因为这个盒子实时很好。此外,即使对于一个用户来说,正常页面加载的900毫秒也太慢,所以如果可能的话,我们希望避免这种情况。

有没有人对我如何加快速度有任何想法?我目前的两个想法是:

  • 一个新的数据库表,用于保存最后一个不需要加入的玩家
  • 存储在某个地方的字段,其中包含该框的HTML,每次发生重建该字段的新游戏
  • 两者的结合

两种丑陋!任何帮助表示赞赏。

根据要求,linqpad结果

LAMBDA

TblArcadeGamePlays
   .Join (
      TblProfiles, 
      c => c.UserID, 
      a => a.UserID, 
      (c, a) => 
         new  
         {
            c = c, 
            a = a
         }
   )
   .Where (temp0 => (temp0.c.UserID != 0))
   .Select (
      temp0 => 
         new  
         {
            UserID = temp0.c.UserID, 
            Username = temp0.c.User.Username, 
            EmailAddress = temp0.a.EmailAddress, 
            Date = TblArcadeGamePlays
               .Where (d => (d.UserID == temp0.c.UserID))
               .OrderByDescending (d => d.Date)
               .Select (
                  d => 
                     new  
                     {
                        Date = d.Date
                     }
               )
               .Take (1)
               .Single ().Date
         }
   )
   .Distinct ()
   .OrderByDescending (c => c.Date)
   .Take (16)

SQL

-- Region Parameters
DECLARE @p0 Int = 0
-- EndRegion
SELECT TOP (16) [t6].[UserID], [t6].[Username], [t6].[EmailAddress], [t6].[value] AS [Date2]
FROM (
    SELECT DISTINCT [t5].[UserID], [t5].[Username], [t5].[EmailAddress], [t5].[value]
    FROM (
        SELECT [t0].[UserID], [t2].[Username], [t1].[EmailAddress], (
            SELECT [t4].[Date]
            FROM (
                SELECT TOP (1) [t3].[Date]
                FROM [tblArcadeGamePlays] AS [t3]
                WHERE [t3].[UserID] = [t0].[UserID]
                ORDER BY [t3].[Date] DESC
                ) AS [t4]
            ) AS [value]
        FROM [tblArcadeGamePlays] AS [t0]
        INNER JOIN [tblProfile] AS [t1] ON [t0].[UserID] = [t1].[UserID]
        INNER JOIN [tblForumAuthor] AS [t2] ON [t2].[Author_ID] = [t0].[UserID]
        ) AS [t5]
    WHERE [t5].[UserID] <> @p0
    ) AS [t6]
ORDER BY [t6].[value] DESC

查询计划

enter image description here

4 个答案:

答案 0 :(得分:5)

我愿意投入相当不错的钱,几乎所有你看到的延迟都来自数据库本身,而不是LINQ(使这成为数据库优化问题,而不是LINQ优化问题)。

我使用linqpad来查看正在生成的查询(请参阅:http://www.thereforesystems.com/view-t-sql-query-generated-by-linq-to-sql-using-linqpad/),并在此处发布。

在SQL Management Studio中运行该查询的查询计划(假设您使用的是SQL Server)也很有帮助。

好的,鉴于编辑,请尝试这样的事情。它应该大大简化查询:

using (MainContext db = new MainContext())
{
    var latestIds = db.tblArcadeGamePlays.OrderByDescending(c => c.Date).Select(c => c.UserID).Distinct().Take(16); // These are the 16 most recent player Ids.
    // join them here to the rest of those player's data
    var playerData = ... // you'll need to fill in here some by filtering the other data you want using latestIds.Contains
}

答案 1 :(得分:1)

这可能不是问题,但您的日期查询可以简化为:

Date = (from d in db.tblArcadeGamePlays 
        where d.UserID == c.UserID 
        orderby d.Date descending 
        select d.Date).First()

也许圆形查询让优化器混乱。否则我同意其他答案,检查生成的SQL查询并检查索引。

另外,您确定Distinct是否必要,并且它符合您的想法?它只会过滤掉每个字段/列具有相同值的重复项。

答案 2 :(得分:0)

确保在联接的两侧都有索引。

答案 3 :(得分:0)

使用这些查询针对您的数据库运行SQL Server数据库调优向导(在SQL Management Studio / Tools中),并让它创建统计信息和索引以调整数据库的性能。 有多少人会推荐这个?它有效。