2012-07-23 43 views
0

在我們的應用程序中,我們使用Windows服務生成報告。報告數據從SQL Server使用存儲過程獲取。在某些情況下,返回的結果集包含250,000條記錄(我們無法幫助完成此部分,因爲我們需要對此進行一些計算)。C#OutOfMemory處理大數據時的問題

問題

我們的應用程序在獲得讀者這個數據,我們正在我們的自定義對象的自定義集合在轉換數據集。由於數據量巨大,因此無法將完整的數據存儲在自定義對象中,因此無法存儲內存。當我們在執行記錄時看到進程使用情況的任務管理器時,它非常高,甚至CPU利用率也很高。

我不確定在這種情況下應該做什麼。

  1. 我們可以增加分配給CLR下運行一個進程內存的大小?
  2. 其他解決方法?

任何幫助將非常感激

  1. 爲什麼我需要一次所有的數據:我們需要做完整的結果集計算
  2. 我們使用ADO.NET和轉化將數據設置到我們的自定義對象中(集合)
  3. 我們的系統是32位
  4. 我們無法頁面數據
  5. 不能計算移動到SQL Server

此堆棧跟蹤可能會幫助:類型的System.OutOfMemoryException'的

異常被拋出。服務器 堆棧跟蹤:在 System.Collections.Generic.Dictionary 2.ValueCollection.System.Collections.Generic.IEnumerable<TValue>.GetEnumerator() at System.Linq.Enumerable.WhereEnumerableIterator 1.MoveNext()在 System.Collections.Generic.List 1.InsertRange(Int32 index, IEnumerable 1集)在 System.Collections.Generic.List 1.AddRange(IEnumerable 1集) 在MyProject的。 Common.Data.DataProperty.GetPropertiesForType(Type t)in C:\ Ashish-Stuff \ Projects \ HCPA \ Dev Branch \ Common \ Benefits.Common \ Data \ DataProperty.shared.cs:line 60 at MyProject.Common。 Data.Extensions.GetProperties [T](T target)in C:\ Ashish-Stuff \ Projects \ HCPA \ Dev Branch \ Common \ Benefits.Common \ Data \ Extensions.shared.cs:line 30 at MyProject.Common .Data.Factories。SqlServerDataFactoryContract 1.GetData(String procedureName, IDictionary 2個參數,可爲空1 languageId, Nullable 1 PAGENUMBER,Nullable`1的pageSize)

感謝, 阿希什

+2

你需要_all_行嗎? – 2012-07-23 15:05:33

+1

您應該調查您是否可以執行SQL中的部分或全部計算。例如,您可能能夠將結果總結爲少於250萬行,然後繼續在C#中處理。 – 2012-07-23 15:05:35

+2

我們需要更多信息。例如操作系統是32位或64位操作系統。 250萬條記錄不算什麼,有些系統處理數十億條記錄,他們只是把它們放在切片中然後合併它們。至於我低估這個問題的原因,你需要提供代碼並告訴我們你目前是如何處理這個問題的,所以我們可以解決你的下劃線問題。 – 2012-07-23 15:06:31

回答

0

你能每1000行數據,對象序列化的自定義收集到磁盤的地方?那麼當你返回數據時,從這些文件分頁?

有關您的用例的更多信息,爲什麼您需要撤回250萬行數據將會有所幫助。

+0

它可能只有250K。 '2,50,000'是你如何在印度表達的。 – 2012-07-23 15:43:24

+0

是的,它的250K :) – 2012-07-23 15:51:19

0

我的第一個雖然是計算可以在Sql-Server端由一些存儲過程。我懷疑這種方法需要一些Sql-Server jedi ...但無論如何,你有沒有考慮過這種方法?

+0

計算有點複雜,並且還需要其他數據(這已經可用@ c#端),所以不能認爲.. – 2012-07-23 16:09:36

+0

好吧,這很清楚。要求似乎有點艱難。然後,我建議你不是通過dataadapter將數據加載到數據集中,而是通過datareader將數據加載到自定義實例(結構?)的集合中,使用'string.Interns(string s)方法'和google進一步研究「c#內存優化」 [this one](http://geekswithblogs.net/robp/archive/2008/08/07/speedy-c-part-2-optimizing-memory-allocations---pooling-and.aspx)或[this]( http://www.dotnetperls.com/optimization); – 2012-07-24 08:31:39

0

我很想看到一個代碼示例突出顯示你正在從哪裏得到這個錯誤。它是在數據拉本身上(填充閱讀器)還是創建對象並將其添加到自定義集合(填充集合)。

我以前遇到過類似的問題,處理非常大的數據集,但在儘可能長的時間內將它留在流中取得了巨大的成功。流會將數據直接保存在內存中,直到完成構建對象時,您纔會真正擁有直接訪問整個混亂的任何內容。現在,鑑於堆棧跟蹤在「MoveNext」操作中顯示錯誤,這可能不適用於您。然後我會說嘗試分塊數據,一次抓取10k行或者其他東西,我知道這可以用SQL來完成。它會使讀取的數據花費更長的時間。

編輯

如果從數據庫中讀取到這個地方流,你再傳給身邊(只是要小心,不要將其關閉),那麼你應該不會遇到這些問題。製作一個數據包裝類,您可以使用開放式流和開放式閱讀器傳遞。將數據存儲在流中,然後使用包裝函數從中讀取您需要的特定數據。諸如GetSumOfXField()AverageOfYValues()等等......數據永遠不會存在於活動對象中,但您不必爲此繼續返回數據庫。

僞例

public void ReadingTheDataFunction() 
    { 
     DBDataReader reader = dbCommand.ExecuteReader(); 
     MyDataStore.FillDataSource(reader) 
    } 

    private void FillDataSource(DbDataReader reader) 
    { 
     StreamWriter writer = new StreamWriter(GlobaldataStream); 
     while (reader.Read()) 
      writer.WriteLine(BuildStringFromDataRow(reader)); 
     reader.close(); 
    } 

    private CustomObject GetNextRow() 
    { 
     String line = GlobalDataReader.ReadLine(); 
     //Parse String to Custom Object 
     return ret; 
    } 

從那裏,你繞過MyDataStore,只要流和讀者都沒有關閉,你可以四處移動你的位置,去尋找各個條目,編譯總和和平均值等等,你甚至不必真正知道你不是在處理一個活的對象,只要你只通過接口函數與它進行交互。

+0

我在填充自定義對象時遇到此錯誤。 – 2012-07-24 01:26:39

+0

我認爲你唯一的選擇就是將它留在記憶中。將數據保存或加載到流中,並使用讀取器訪問它,或將其分頁到磁盤上的文件或文件集中,然後使用讀取器訪問它。 – Nevyn 2012-07-24 12:33:41

+0

我會嘗試這種方式,讓你知道結果.. – 2012-07-24 16:17:21