5

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

为什么.ToList()要花这么长时间?以及如何改进?

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

这是ANTS的屏幕截图:

在此处输入图像描述

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

在此处输入图像描述

确凿证据:.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();

这有帮助吗?

4

5 回答 5

9

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

在此处阅读有关延迟执行的更多信息。

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

于 2013-05-29T11:00:25.893 回答
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 服务器的连接很慢
  3. 您的 lambda 表达式树很复杂,实体框架需要很长时间来处理它并生成 T-SQL

我将首先打开 SQL 分析器并查看 SQL。即使看起来最简单的语句也可能做一些疯狂的事情,唯一确定的方法是查看实际的 T-SQL。

如果 T-SQL 没问题,您将不得不使用 Lambda 表达式以使其更简单、更易于处理。

于 2013-05-29T11:00:33.083 回答
3

Linq2SQL 使用称为延迟加载的东西。基本上,在您查看您要求的容器之前,它不会靠近数据源。您可以继续构建您的查询,但是一旦您列出它,或者查看第一个,它就会构建您的查询,将其发送到数据库并等待结果......因此需要很长时间

于 2013-05-29T11:00:26.880 回答
2

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

请记住,查询只会在您调用时执行ToList。在那之前,它只是一个可查询的对象。使用 SQL 分析器查看它,您会看到在执行数据库访问时。

于 2013-05-29T11:01:50.193 回答
1

好吧,毕竟,事实证明 ANTS 是在对我们做海森堡。

事情的结果是,我最初收到了关于这方面表现不佳的投诉。我运行了 ANTS 并确定该代码是负责任的。所以我重构,优化,结果就是你在问题中看到的代码。然后我重新测试,发现有很大的改进,但性能仍然无法接受。然后是SO问题。

然后我决定尝试在没有 ANTS 的情况下运行单元测试......它在几分之一秒内运行。

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

于 2013-05-29T12:33:38.593 回答