2013-05-01 88 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.