两个数据库的ASP.NET MVC LINQ性能问题

时间:2016-12-23 17:40:43

标签: c# asp.net-mvc linq

我在ASP.NET MVC应用程序中工作,并有两个不同的连接(数据库)。这就像用户进行一些小型考试的应用程序。在一个页面上,我必须向用户显示所有详细信息的考试/活动:何时,哪些结果以及有关活动/考试的所有详细信息。在红色数据库中只有关于结果,时间,用户和activityid的信息 - 因此您可以在另一个(蓝色)数据库中获取该跟踪的活动。每项活动最多可以完成5次。

我尝试了几种不同的查询,但性能非常非常慢。您有什么想法我如何解决此查询,用户不必在页面上等待10秒钟?

谢谢!

enter image description here

修改

跟踪表(db1,表1)现在有1732982条记录,并且它总是在增长,因为用户可以随时进行检查。目前有1832项活动来自110课。

下面详细的数据库图片(这是我得到的,所以我必须使用它但我可以根据需要更改ids / pk / fk - 或者更改我需要的任何内容,但它必须保留在两个不同的数据库中):

enter image description here

以下是用于获取一个用户的结果的代码。 UserId像函数中的参数一样发送,并在此代码中使用。

        IList<TrackingCustomModel> result = new List<TrackingCustomModel>();
        using (DATA.examContent.Model ctc = new DATA.examContent.Model()) //first database (activities, lessons)
        {
            using (Model ctx = new Model()) //this is second database (tracking)
            {
                // Get all Activities
                IList<Activity> ac = ctc.Activity.Include("Lesson").ToList();
                char[] trimChars = { '0' };
                IEnumerable<TrackingCustomModel> q;
                    q = from a in ac
                        select new TrackingCustomModel
                        {
                            ActivityId = a.Id,
                            LessonCode = a.Lesson.Code.TrimStart(trimChars),
                            ActivityCode = a.Code.TrimStart(trimChars),
                            ActivityHead = a.Head.Trim()
                        };
                IList<TrackingCustomModel> add = q.ToList<TrackingCustomModel>();
                // Get all Trackings for userId
                IList<Tracking> tr = ctx.Tracking.Where(t => t.UserId == userId).ToList();

                // Join Activites with Tracking of User, and Calculate Scores
                var s = from a in add
                        join t in tr on a.ActivityId equals t.ActivityId
                        orderby t.Timestamp descending
                        select new TrackingCustomModel
                        {
                            ActivityId = a.ActivityId,
                            LessonCode = a.LessonCode,
                            ActivityCode = a.ActivityCode,
                            ActivityHead = a.ActivityHead,
                            Timestamp = DefaultHelper.AdjustDateToLocalTimezone(t.Timestamp),
                            ActivityHits = t.ActivityHits,
                            ActivityMistakes = t.ActivityMistakes,
                            ActivityScore = (t.ActivityHits + t.ActivityMistakes) > 0 ? (String.Format("{0:0%}", (Decimal.Divide(t.ActivityHits, (t.ActivityHits + t.ActivityMistakes))))).ToString() : null
                        };


                // Group the results by Activity and calculate the Activity average

                var group = from t in s
                            group t by t.ActivityId into g
                            select g;
                foreach (IGrouping<Guid, TrackingCustomModel> g in group)
                {
                    TrackingCustomModel thc = (from t in g
                                               where t.ActivityId == g.Key
                                               select t).FirstOrDefault();

                    IList<TrackingCustomModel> multipleTry = (from d in s
                                                              where d.ActivityId == g.Key
                                                              select d).ToList();
                    if (multipleTry.Count > 1)
                    {
                        thc.ActivityDone = multipleTry.Count.ToString();
                        Decimal scoreAsDecimal;
                        Decimal averageScore = 0;
                        foreach (TrackingCustomModel t in multipleTry)
                        {
                            if (t.ActivityHits != 0)
                            {
                                scoreAsDecimal = (Decimal.Divide(t.ActivityHits, (t.ActivityHits + t.ActivityMistakes)));
                                averageScore += scoreAsDecimal;
                            }
                        }
                        averageScore /= multipleTry.Count;
                        if (averageScore != 0)
                        {
                            thc.AverageScore = String.Format("{0:0%}", averageScore).ToString();
                        }
                        else
                        {
                            thc.AverageScore = "";
                        }
                    }
                    else
                    {
                        thc.ActivityDone = "";
                    }
                    result.Add(thc);
                }
            }
        }
        return result;

1 个答案:

答案 0 :(得分:0)

  1. 从数据库1获取所有相关活动的列表。
  2. 从数据库2获取所有活动信息+课程信息
  3. 找到什么是慢,1还是2?
  4. 慢活动列表查询(步骤1)

    确保索引where where子句。例如。 UserId,可能包括DateTime?

    慢活动信息/课程信息查询(步骤2)

    确保将Activity.ActiviyID编入索引,因为这是您在第二个查询中应该搜索的内容。

    课程信息应该由Lesson.LessonID搜索,应该编入索引

    如果使用EF,请执行

    var res = Activities        
        .Include(x => x.Lesson) 
        .Where(x => activityIds.Contains(x.AcitivityID))
        .ToList()
    

    从活动中将课程带入一个电话中。

    否则如果使用自定义SQL,请添加连接,例如

    SELECT * FROM Table1 a JOIN Table2 b ON a.LessonID = b.LessonID

    并确保正确映射。

    其他注意事项

    • 缓存课程信息(如果这不经常更改)
    • 您有多少活动/课程
    • 您目前如何查询对象?确保你不是懒得加载整棵树,因为这会导致你为每个独特的实体点击数据库!

    RE:编辑1

    不确定数据库中有多少数据,但请注意代码中的以下查询:

     IList<Activity> ac = ctc.Activity.Include("Lesson").ToList();
    
    1. 这将在表格中所有活动
    2. .Include("Lesson")会复制具有相同ID的课程,可能导致无法获取大量数据
    3. e.g。如果您有1节课,但有50个活动,那么您将为这50个活动中的每个活动检索一个单独的课程实例(即使它们是相同的)。