Linq查询在几分之一秒内运行,但.ToList()需要3.5秒

时间:2013-05-29 10:58:19

标签: c# linq linq-to-entities entity-framework-5

我正在运行Linq查询,该查询返回大约25条记录,每条记录包含10个数字列。根据我的代码分析器,查询本身只需要几分之一秒 - 但对.ToList()的调用大约需要3.5秒。如上所述,从SQL返回的数据量是微不足道的,因此将其复制到List所需的时间不应该是繁重的。

为什么.ToList()花了这么长时间?怎么可以改进呢?

编辑:赞赏所有快速答案,让我更清楚地说明一下:我完全知道查询是延迟加载的事实。我看到的现象是,SQL Server Profiler和ANTS Performance Profiler都报告实际查询执行时间只是一小部分。

这是来自ANTS的屏幕截图:

enter image description here

请注意,调用方法需要4.3秒,而实际的SQL查询都不会超过.05秒。可能是该方法中的其他代码,而不是SQL?让我们看看ANTS如何在这里分解代码配置文件:

enter image description here

抽烟枪证明:.ToList()需要3.36秒,其中0.05秒可归因于实际查询执行时间,留下3.31秒无法计算。

那个时间到了哪里?

编辑2:好的,你问过它,所以这是我的代码:

public static Expression<Func<Student, Chart>> GetStudentAssessmentQuestionResultByStudentIdNew(MyDataEntities db)
{
    return s => new Chart
        {
            studentID = s.ID,
            Lines =
                    db.StudentAssessmentAnswers
                        .Where(
                                saa =>
                                saa.StudentAssessment.BorrowedBook.StudentID == s.ID && saa.PointsAwarded != null &&
                                saa.Question.PointValue > 0 &&
                                (saa.Question.QuestionType == QuestionType.MultipleChoice ||
                                 saa.Question.QuestionType == QuestionType.OpenEnded))
                        .GroupBy(
                                saa =>
                                new
                                {
                                    saa.StudentAssessment.AssessmentYear,
                                    saa.StudentAssessment.AssessmentMonth,
                                    saa.Question.CommonCoreStandard
                                },
                                saa => saa)
                        .Select(x => new
                                     {
                                         x.Key.AssessmentYear,
                                         x.Key.AssessmentMonth,
                                         x.Key.CommonCoreStandard,
                                         PercentagePointValue =
                                         (float)(x.Sum(a => a.PointsAwarded) * 100) / (x.Sum(a => a.Question.PointValue))
                                     })
                        .OrderByDescending(x => x.CommonCoreStandard)
                        .GroupBy(r1 => (byte)r1.CommonCoreStandard)
                        .Select(g => new ChartLine
                                     {
                                         ChartType = ((ChartType)g.Key),
                                         //type = g.Key.ToString(),
                                         type = g.Key,
                                         Points = g.Select(grp => new ChartPoint
                                                {
                                                    Year = grp.AssessmentYear.Value,
                                                    Month = grp.AssessmentMonth.Value,
                                                    yValue = grp.PercentagePointValue
                                                })
                                     })
        };
}

这称为:

var students =
    db.ClassEnrollments
        .Where(ce => ce.SchoolClass.HomeRoomTeacherID == teacherID)
        .Select(s => s.Student);
var charts = CCProgressChart.GetStudentAssessmentQuestionResultByStudentIdNew(db);
var chartList = students.Select(charts).ToList();

这对你有帮助吗?

5 个答案:

答案 0 :(得分:9)

.ToList()实际上正在执行查询。因此,您的查询需要2.5秒才能运行。

详细了解延期执行here

如果没有发布您的实际LINQ查询,我们无法帮助您提高性能(如果您发布,我会更新我的答案)。

答案 1 :(得分:4)

LINQ to SQL是延迟加载的。在调用ToList()之前,实际上什么也没发生。

编辑:

由于您已经更新了答案,因此需要注意一些事项。 ToList()在构造函数中占73.4%的时间。这是SQL语句实际执行的位置。下面是实际的ToList方法:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
    if (source != null)
    {
        return new List<TSource>(source);
    }
    else
    {
        throw Error.ArgumentNull("source");
    }
}

在调用以下行之前,您的SQL实际上并未执行:

return new List<TSource>(source);

所以是的ToList正在永远,但那是因为它开始处理源参数。 Antz是一个非常有用的工具,但它有时会导致你走错路。问题很可能是其中之一:

  1. 生成的T-SQL很可怕而且很慢。
  2. 打开与SQL Server的连接很慢
  3. 你的lambda表达式树很复杂,实体框架需要很长时间来处理它并生成T-SQL
  4. 我首先要打开SQL分析器并查看SQL。即使看起来最简单的语句也可以做一些疯狂的事情,唯一可以确定的方法就是查看实际的T-SQL。

    如果T-SQL没问题,你将不得不使用你的Lambda表达式来简化它,并且更容易处理。

答案 2 :(得分:3)

Linq2SQL使用了一种名为Lazy Loading的东西。基本上,直到你查看你要求的容器,它不会靠近数据源。您可以继续构建查询,但是只要您对它进行定位,或者查看First,它就会构建您的查询,将其发送到数据库并等待结果....因此需要很长时间

答案 3 :(得分:2)

没有更多细节,很难确定。但是,你的List是什么类型的?该类在构造函数/ setter中做了什么?它是实现INotifyPropertyChanged还是触发任何其他事件?

请记住,只有在您致电ToList时才会执行查询。直到那时,它只是一个可查询的对象。使用SQL事件探查器查看它,当它进行数据库访问时,您将看到

答案 4 :(得分:1)

嗯,毕竟,事实证明ANTS正在对我们做海森堡。

事情的发展方式是我最初抱怨这个领域表现不佳。我运行ANTS并确定此代码是负责任的。所以我重构,优化,结果就是你在问题中看到的代码。然后我重新测试,发现了一个显着的改进,但性能仍然是不可接受的。然后是SO问题。

然后我决定尝试在没有ANTS的情况下运行单元测试......并且它在不到一秒的时间内运行。

经验教训:有时,性能分析器本身就是性能不佳的原因。