Linq-to-Sql Sproc -- ToList() is Too Slow
本文关键字:is Too Slow Sproc ToList Linq-to-Sql | 更新日期: 2023-09-27 18:11:48
我正在使用Linq2Sql返回存储过程的结果。存储过程在2秒内提供100000条记录。应用ToList((需要2分钟以上的时间。
该项目是ASP.NET WebForm。在后面的代码中,我试图从事务系统中获取记录,以便为仪表板类型的报告应用各种分析。10万条记录是平均一个月的数据。对于较小的数据,一切都很好。
using (FooDataContext dbml = new FooDataContext())
{
var query = dbml.FooBar(OneParam, TwoParam, ThreeParam);
//no delay
var results = query.ToList();
//takes over 2 minutes -- consistent network traffic throughout
ReportGenerator.PivotTable(results);
ReportGenerator.Chart(results);
//etc.
}
我使用ToList((来利用Linq的水合存储过程对象,这对于使用lambda表达式评估结果非常方便。
但是ToList((需要非常非常长的时间来构造这么多数据的每个结果。如果在此期间暂停进程,我可以看到它只是通过存储过程的构造函数一次又一次地循环。查看我的网络流量似乎可以确认代码正在返回到每个对象的数据库。将DeferredLoadingEnabled设置为false没有帮助。
有趣的是,我认为存储过程的一个缺点是它们一次将所有数据转储回您,而不是作为IQueryable?
我认为您试图以一种非最优的方式解决问题。如果你想提供仪表板报告,你应该有后台流程(可能是sql代理作业或windows服务(来构建物化的仪表板表,将数字处理成更小的"报告dto",然后你可以查询并将其放入你的仪表板中。我不在乎SQL是什么,每次请求提取10万条记录,然后执行一些计算/处理以有意义的方式显示数据,这将是浪费,而且执行速度较慢。
在获取记录时尝试执行TOList((。这可能效果很快。var query = dbml.FooBar(OneParam, TwoParam, ThreeParam).Tolist();
并像一样直接使用集合
ReportGenerator.PivotTable(query);
ReportGenerator.Chart(query);
对我来说,解决方案是使用老式的ADO.NET来查询存储的过程。显然没有L2S那么容易,但在这种情况下,它似乎比L2S更快地为每一行运行该过程。
public List<object> Foo(SqlConnection connection)
{
var query = "[dbo].[FooBar]";
var command = new SqlCommand(query, connection);
command.CommandType = CommandType.StoredProcedure;
connection.Open();
var reader = command.ExecuteReader();
var results = new List<object>(); // Or whatever type your data is.
while (reader.Read())
{
// Make this work for your particular data structure:
results.Add(reader.GetString(0));
}
connection.Close();
return results;
}
此外,为了安全起见,一定要使用using语句创建连接:
using (var connection = new SqlConnection(connectionString))
{
results = Foo(connection);
}
ReportGenerator.PivotTable(results);
ReportGenerator.Chart(results);
//etc.