2013-05-01 46 views
1

我正在使用Linq2Sql来返回存储过程的结果。 sproc在2秒内提供100,000条记录。应用ToList()需要2分钟以上。Linq-to-Sql Sproc - ToList()太慢

该项目是一个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的水合存储过程的对象,这是很方便的用于评估与lambda表达式的结果。

但ToList()需要非常很长的时间来为这些数据构造每个结果。如果我在那段时间暂停过程,我可以看到它只是通过sproc的构造函数循环遍历。看着我的网络流量似乎证实代码将返回到每个对象的数据库。将DeferredLoadingEnabled设置为false并没有帮助。

有趣的是,我认为存储过程的一个缺点是他们一次性将所有数据都转回给你,而不是IQueryable?

+0

我不认为这个框架可以推迟装载存储过程的结果。每个记录有多大? – tia 2013-05-01 23:48:47

+0

存储过程需要多长时间才能在LINQ之外运行? – 2013-05-02 17:07:37

+0

“sproc在2秒内提供100,000条记录”在什么情况下?当通过SSMS或其他查询工具运行时? “FooBar”返回什么类型?那种类型的构造函数是否在做任何可能会减慢速度的东西? – 2013-05-02 17:09:54

回答

2

我认为你正在试图解决的方式是不是最优的问题集合。如果您想提供仪表板报告,则应该有后台进程(可能是SQL代理作业或Windows服务)来构建物化仪表板表,并将数字缩减为较小的“报告dtos”,然后您可以查询并将其放入仪表板。我不在乎SQL是什么,每个请求提取100k条记录,然后执行一些计算/处理以有意义的方式显示数据会浪费并且执行速度慢。

+0

我并不反对,坦率地说,恐怕可能是这种情况,但我正在尝试做的建模只是更适合C#的过程能力,而不是T-SQL的基于集合的操作....处理服务器端的高保真数据更容易,更强大,更易维护,所以我希望找到解决方案。但也许这对于L2S来说太多了。 – RJB 2013-05-02 20:10:05

+0

相信我,我的回答是基于我自己的努力尝试做到这一点。在试图调整请求超时,客户期望值,不断变化的生产数据记录数量等方面,玩过永无止境的猫和老鼠后,我刚刚得出结论,在后台进程中这样做是最好的方式。您不必在SQL中执行此操作,可以在另一个进程(Windows服务或计划任务控制台应用程序)中处理C#中的数据,然后将该处理的输出保存在专用于仪表板Web请求的表中。 – BlakeH 2013-05-02 20:41:09

0

尝试在收到记录的那一刻做TOList()。这可能工作得很快。 var query = dbml.FooBar(OneParam, TwoParam, ThreeParam).Tolist();和直接使用像

ReportGenerator.PivotTable(query); 
ReportGenerator.Chart(query); 
+3

在一条线上对两条做不会改变任何东西。 – 2013-05-02 17:05:59

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.