提高代码性能

时间:2016-07-25 08:37:51

标签: c# entity-framework optimization foreach

我有一个cron-job方法,它根据用户的特色故事构建用户的故事提要,跟随类别并跟踪用户。

最终Feed以正确的顺序添加到下面的数据库表中:
UserFeed表:

Uid StoryListIds
1 3,23,45,3,6,234,....... 2 3,23,45,6,87,44,....... 3 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 个答案:

答案 0 :(得分:1)

很难准确地说出导致它执行得如此缓慢的原因,因为我建议使用SQL Server Profiler来分析您的问题。检查您的查询是否被正确询问,并且没有做任何不必要的事情。

之后,我会考虑提出更少的问题。由于您在循环中执行此操作,因此可以从更少,但更重的问题中受益。例如(假设userFollowersBL。*正在查询数据库):

class myClass
{
  public function methodReturnsTrue()
  {
    return true;
  }
}

我认为签名是这样的:

var followedCategoryIds = userCategoriesBL.GetFollowedCategoryIds(userId);

考虑将其更改为:

IEnumerable<int> GetFollowedCategoryIds(userId);

然后,在开始使用foreach之前,您将在内存中找到包含userid和每个followCategoryIds的字典。这样,您就可以在一个查询中发送IDictionary<int, IEnumerable<int>> GetFollowedCategoryIds(IEnumerable<int> userIds); 的所有结果。 可能可以提高性能,而不是30次。同样适用于userBL.GetIds()

现在,您已使用约58次减少了对您的数据库的查询次数。

userFollowersBL.GetFollowedUserIds(userId)

但老实说,这主要是猜测,可能会不时发生变化。根据我的经验,您往往会从一次请求更多数据中受益,而不是多次使用相同的数据。