我正在使用Linq2Sql来返回存储过程的结果。 sproc在2秒内提供100,000条记录。应用ToList()需要2分钟。
该项目是一个ASP.NET WebForm。在代码隐藏中,我试图从事务系统中获取记录,以便为仪表板类型报告应用各种分析。 100K记录是平均月份的数据。使用较小的数据,一切正常。
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的水合sproc对象,这对于使用lambda表达式评估结果很方便。
但ToList()需要非常长的时间来构建这么多数据的每个结果。如果我在那段时间暂停这个过程,我可以看到它只是在sproc的构造函数中循环遍历。查看我的网络流量似乎确认代码将返回到每个对象的数据库。将DeferredLoadingEnabled设置为false没有帮助。
有趣的是,我认为存储过程的一个缺点是它们会立即将所有数据丢弃给您,而不是作为IQueryable?
答案 0 :(得分:2)
我认为您正试图以不是最佳的方式解决问题。如果要提供仪表板报告,则应该有后台进程(可能是sql代理作业或Windows服务)构建物化仪表板表,其中的数字会缩小为较小的“报告dtos”,然后您可以查询并放入仪表板。我不关心SQL是什么,每个请求提取100k记录然后执行一些计算/处理以有意义的方式显示数据将会浪费并且执行速度较慢。
答案 1 :(得分:0)
在获取记录时尝试执行TOList()。这可能很快。
var query = dbml.FooBar(OneParam, TwoParam, ThreeParam).Tolist();
并直接使用该集合,如
ReportGenerator.PivotTable(query);
ReportGenerator.Chart(query);
答案 2 :(得分:0)
我的解决方案是使用旧式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.