我正在运行Linq查询,该查询返回大约25条记录,每条记录包含10个数字列。根据我的代码分析器,查询本身只需要几分之一秒 - 但对.ToList()
的调用大约需要3.5秒。如上所述,从SQL返回的数据量是微不足道的,因此将其复制到List
所需的时间不应该是繁重的。
为什么.ToList()
花了这么长时间?怎么可以改进呢?
编辑:赞赏所有快速答案,让我更清楚地说明一下:我完全知道查询是延迟加载的事实。我看到的现象是,SQL Server Profiler和ANTS Performance Profiler都报告实际查询执行时间只是一小部分。
这是来自ANTS的屏幕截图:
请注意,调用方法需要4.3秒,而实际的SQL查询都不会超过.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();
这对你有帮助吗?
答案 0 :(得分:9)
答案 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是一个非常有用的工具,但它有时会导致你走错路。问题很可能是其中之一:
我首先要打开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的情况下运行单元测试......并且它在不到一秒的时间内运行。
经验教训:有时,性能分析器本身就是性能不佳的原因。