2016-07-25 68 views
0

我有一个cron-job方法,它根据用户的精选故事,后续类别和关注用户构建用户的故事馈送。提高代码性能

最终进料在以下数据库表中加入正确的顺序:
UserFeed表:

的Uid         StoryListIds
              3,23, 45,3,6,234,.....
              3,23,45,6,87,44,...
              3,23,45,32,如图4所示,62,... ..

该方法如下,并包含注释。
的代码:

public void ConstructUserFeed() 
     { 
      try 
      { 
       //get all user ids 
       var userIds = userBL.GetIds(); 
       //get all featured stories 
       var featStories = storyBL.GetFeaturedStories(); 

       if (userIds != null && userIds.Count > 0) 
       { 
        foreach (var userId in userIds) 
        { 
         //integer List to store the stories ids in correct order 
         List<int> storyIdsLst = new List<int>(); 
         //integer List for excluding duplicates 
         List<int> exceptStoryIds = new List<int>(); 
         //user feed List to store the stories 
         var userFeed = new List<UserFeedDTO>(); 
         //string to store the id list so we can add it later in db 
         string storyIds = ""; 

         if (featStories != null && featStories.Count > 0) 
         { 
          foreach (var featStory in featStories) 
          { 
           //first add all the ids of featured stories except own user stories, ordered by date 
           if (featStory.authorId != userId) 
           { 
            storyIdsLst.Add(featStory.id); 
            exceptStoryIds.Add(featStory.id); 
           } 
          } 
         } 

         //get user's followed categories ids 
         var followedCategoryIds = userCategoriesBL.GetFollowedCategoryIds(userId); 

         if (followedCategoryIds != null && followedCategoryIds.Count > 0) 
         { 
          foreach (var categoryId in followedCategoryIds) 
          { 
           //get the user's 5 latest stories for every followed category 
           //except own stories and previous stories 
           var storiesByCateg = storyBL.GetByCategory(5, categoryId, userId, exceptStoryIds); 

           if (storiesByCateg != null && storiesByCateg.Count > 0) 
           { 
            foreach (var storyByCateg in storiesByCateg) 
            { 
             userFeed.Add(storyByCateg); 
             exceptStoryIds.Add(storyByCateg.id); 
            } 
           } 
          } 
         } 

         //get user's followed users ids 
         var followedUserIds = userFollowersBL.GetFollowedUserIds(userId); 

         if (followedUserIds != null && followedUserIds.Count > 0) 
         { 
          foreach (var followedId in followedUserIds) 
          { 
           //get the user's 5 latest stories for every followed user 
           //except own stories and previous stories 
           var storiesByFollowedUsers = storyBL.GetByFollowedUser(5, followedId, userId, exceptStoryIds); 

           if (storiesByFollowedUsers != null && storiesByFollowedUsers.Count > 0) 
           { 
            foreach (var storyByFollowedUsers in storiesByFollowedUsers) 
            { 
             userFeed.Add(storyByFollowedUsers); 
            } 
           } 
          } 
         } 

         // order the stories by date 
         userFeed = userFeed.OrderByDescending(story => story.dateAdded).ToList(); 

         if (userFeed != null && userFeed.Count > 0) 
         { 
          foreach (var story in userFeed) 
          { 
           //add the story ids after the featured story ids 
           storyIdsLst.Add(story.id); 
          } 
         } 

         //comma separated list of story ids as string so we can store it in db 
         storyIds = string.Join(",", storyIdsLst.Select(n => n.ToString()).ToArray()); 

         //create the UserFeed model 
         UserFeed userFeedModel = new UserFeed(); 
         userFeedModel.userId = userId; 
         userFeedModel.storyListId = storyIds; 
         userFeedModel.lastUpdateTime = DateTime.Now; 

         userFeedBL.AddOrUpdateUserFeed(userFeedModel); 
        } 
        uof.Save(); 
       } 
      } 

      catch (Exception ex) 
      { 
       Console.WriteLine("Error occurred in processing job. Error : {0}", ex.Message); 
      } 
     } 

,上述方法需要〜35秒来完成30个用户。
问:我该如何改进我的代码和性能?

+1

你可以考虑在存储过程中使用它吗? –

回答

1

很难说究竟是什么原因导致它执行得太慢,因为我建议用SQL Server Profiler来分析你的问题。检查您的查询是否被正确询问,并且没有做任何不必要的事情。

之后,我会考虑询问更少的问题。既然你在做循环,你可能会受益于更少,但更重的问题。例如(假设userFollowersBL *被查询DB):

var followedCategoryIds = userCategoriesBL.GetFollowedCategoryIds(userId); 

我认为签名是这样的:

IEnumerable<int> GetFollowedCategoryIds(userId); 

考虑将其更改为:

IDictionary<int, IEnumerable<int>> GetFollowedCategoryIds(IEnumerable<int> userIds); 

然后你在开始你的foreach之前,会有一个字典,其中包含userids和他们的每个followCategoryId。通过这种方式,您可以在一个查询中发送来自userBL.GetIds()的所有结果。它可能加速性能做一次,而不是30次。 userFollowersBL.GetFollowedUserIds(userId)也是一样。

现在您已减少查询数量到您的DB与约58倍

public void ConstructUserFeed() 
     { 
      try 
      { 
       //get all user ids 
       var userIds = userBL.GetIds(); 
       //get all featured stories 
       var featStories = storyBL.GetFeaturedStories(); 

// Fetch all in one query. 
IDictionary<int,IEnumerable<int>> allFollowedCategoryIds= userCategoriesBL.GetFollowedCategoryIds(userIds); 
// Fetch all in one query 
IDictionary<int,IEnumerable<int>> allUserFollowers = userFollowersBL.GetFollowedUserIds(userIds); 

       if (userIds != null && userIds.Count > 0) 
       { 
        foreach (var userId in userIds) 
        { 
         //integer List to store the stories ids in correct order 
         List<int> storyIdsLst = new List<int>(); 
         //integer List for excluding duplicates 
         List<int> exceptStoryIds = new List<int>(); 
         //user feed List to store the stories 
         var userFeed = new List<UserFeedDTO>(); 
         //string to store the id list so we can add it later in db 
         string storyIds = ""; 

         if (featStories != null && featStories.Count > 0) 
         { 
          foreach (var featStory in featStories) 
          { 
           //first add all the ids of featured stories except own user stories, ordered by date 
           if (featStory.authorId != userId) 
           { 
            storyIdsLst.Add(featStory.id); 
            exceptStoryIds.Add(featStory.id); 
           } 
          } 
         } 

         //get user's followed categories ids 
         var followedCategoryIds = allFollowedCategoryIds[userId] 

         if (followedCategoryIds != null && followedCategoryIds.Count > 0) 
         { 
          foreach (var categoryId in followedCategoryIds) 
          { 
           //get the user's 5 latest stories for every followed category 
           //except own stories and previous stories 
           var storiesByCateg = storyBL.GetByCategory(5, categoryId, userId, exceptStoryIds); 

           if (storiesByCateg != null && storiesByCateg.Count > 0) 
           { 
            foreach (var storyByCateg in storiesByCateg) 
            { 
             userFeed.Add(storyByCateg); 
             exceptStoryIds.Add(storyByCateg.id); 
            } 
           } 
          } 
         } 

         //get user's followed users ids 
         var followedUserIds = allUserFollowers[userId]; 

         if (followedUserIds != null && followedUserIds.Count > 0) 
         { 
          foreach (var followedId in followedUserIds) 
          { 
           //get the user's 5 latest stories for every followed user 
           //except own stories and previous stories 
           var storiesByFollowedUsers = storyBL.GetByFollowedUser(5, followedId, userId, exceptStoryIds); 

           if (storiesByFollowedUsers != null && storiesByFollowedUsers.Count > 0) 
           { 
            foreach (var storyByFollowedUsers in storiesByFollowedUsers) 
            { 
             userFeed.Add(storyByFollowedUsers); 
            } 
           } 
          } 
         } 

         // order the stories by date 
         userFeed = userFeed.OrderByDescending(story => story.dateAdded).ToList(); 

         if (userFeed != null && userFeed.Count > 0) 
         { 
          foreach (var story in userFeed) 
          { 
           //add the story ids after the featured story ids 
           storyIdsLst.Add(story.id); 
          } 
         } 

         //comma separated list of story ids as string so we can store it in db 
         storyIds = string.Join(",", storyIdsLst.Select(n => n.ToString()).ToArray()); 

         //create the UserFeed model 
         UserFeed userFeedModel = new UserFeed(); 
         userFeedModel.userId = userId; 
         userFeedModel.storyListId = storyIds; 
         userFeedModel.lastUpdateTime = DateTime.Now; 

         userFeedBL.AddOrUpdateUserFeed(userFeedModel); 
        } 
        uof.Save(); 
       } 
      } 

      catch (Exception ex) 
      { 
       Console.WriteLine("Error occurred in processing job. Error : {0}", ex.Message); 
      } 
     } 

但说实话,这主要是猜测,可能会不时地有所不同。根据我的经验,您倾向于从询问更多数据中获益一次,而不是相同的数据多次。

+0

你的意思是创建一个IDictionary 列表为跟随的类别和用户? – alex

+1

是的,但我写错了。我想它需要'IDictionary >' – smoksnes

+0

,减少运行时间到一半,thx – alex