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?

Linq-to-Sql Sproc -- ToList() is Too Slow

我认为您试图以一种非最优的方式解决问题。如果你想提供仪表板报告,你应该有后台流程(可能是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.