2010-08-02 32 views
1

我正在使用SQLBULKCOPY將一些數據表複製到數據庫表中,但是,由於我複製的文件大小有時超過600mb,因此我的內存不足。sqlbulkcopy mem。管理

我希望在將數據提交到數據庫之前得到一些有關管理表大小的建議,這樣我可以釋放一些內存以繼續寫入。

下面是我的一些代碼示例(一些列和行取消了簡單)

  SqlBulkCopy sqlbulkCopy = new SqlBulkCopy(ServerConfiguration); //Define the Server Configuration 
     System.IO.StreamReader rdr = new System.IO.StreamReader(fileName); 

     Console.WriteLine("Counting number of lines..."); 
     Console.WriteLine("{0}, Contains: {1} Lines", fileName, countLines(fileName)); 

     DataTable dt = new DataTable(); 

     sqlbulkCopy.DestinationTableName = "[dbo].[buy.com]"; //You need to define the target table name where the data will be copied 
     dt.Columns.Add("PROGRAMNAME"); 
     dt.Columns.Add("PROGRAMURL"); 
     dt.Columns.Add("CATALOGNAME"); 

     string inputLine = ""; 
     DataRow row; //Declare a row, which will be added to the above data table 

     while ((inputLine = rdr.ReadLine()) != null) //Read while the line is not null 
      { 
       i = 0; 
       string[] arr; 

       Console.Write("\rWriting Line: {0}", k); 
       arr = inputLine.Split('\t'); //splitting the line which was read by the stream reader object (tab delimited) 
       row = dt.NewRow(); 
       row["PROGRAMNAME"] = arr[i++]; 
       row["PROGRAMURL"] = arr[i++]; 
       row["CATALOGNAME"] = arr[i++]; 
       row["LASTUPDATED"] = arr[i++]; 
       row["NAME"] = arr[i++]; 
       dt.Rows.Add(row); 
       k++; 
     } 

     // Set the timeout, 600 secons (10 minutes) given table size--damn that's a lota hooch 
     sqlbulkCopy.BulkCopyTimeout = 600; 
     try 
     { 
      sqlbulkCopy.WriteToServer(dt); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
     } 
     sqlbulkCopy.Close();//Release the resources 
     dt.Dispose(); 

     Console.WriteLine("\nDB Table Written: \"{0}\" \n\n", sqlbulkCopy.DestinationTableName.ToString()); 

    } 

我繼續有問題越來越SqlBulkCopy的工作,我意識到我需要做更多的工作,上每個記錄在它被輸入到數據庫之前,所以我開發了一個簡單的LinQ to Sql方法來記錄更新記錄,所以我可以編輯其他信息並創建更多的記錄信息,因爲它正在運行,

問題:This方法一直運行得很慢w(即使在Core i3機器上),關於如何加速它的任何想法(線程?) - 在單個處理器內核上,1GB內存會崩潰或需要6-8小時來寫入相同數量的數據一個SQLBulkCopy需要一些時間。它確實可以更好地管理內存。

  while ((inputLine = rdr.ReadLine()) != null) //Read while the line is not null 
     { 
      Console.Write("\rWriting Line: {0}", k); 
      string[] arr;    
      arr = inputLine.Split('\t'); 

      /* items */ 
      if (fileName.Contains(",,")) 
      { 
       Item = Table(arr); 
       table.tables.InsertOnSubmit(Item); 

       /* Check to see if the item is in the db */ 
       bool exists = table.tables.Where(u => u.ProductID == Item.ProductID).Any(); 

       /* Commit */ 
       if (!exists) 
       { 
        try 
        { 
         table.SubmitChanges(); 
        } 
        catch (Exception e) 
        { 
         Console.WriteLine(e); 
         // Make some adjustments. 
         // ... 
         // Try again. 
         table.SubmitChanges(); 
        } 
       } 
      } 

隨着helper方法:

public static class extensionMethods 
{ 
    /// <summary> 
    /// Method that provides the T-SQL EXISTS call for any IQueryable (thus extending Linq). 
    /// </summary> 
    /// <remarks>Returns whether or not the predicate conditions exists at least one time.</remarks> 
    public static bool Exists<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) 
    { 
     return source.Where(predicate).Any(); 
    } 
} 
+1

或許還配置了RDR的可能是一個不錯的主意 – 2010-08-02 03:49:21

+0

感謝 - 我會記住這一點 我想知道,如果我提前處理我的讀者在閱讀完每個文件之前,我完成了閱讀程序當我正在閱讀時,我將放鬆自己的步伐,並且在閱讀時出現內存不足錯誤,而我正在寫作... 任何想法我將如何跳回到我在檔案中的位置? – 2010-08-02 07:20:11

+0

請參閱上面的評論... – 2010-08-02 09:27:12

回答

2

嘗試指定BatchSize屬性到1000這將批了一個創紀錄的1000批次,而不是一大堆插件。您可以調整此值以查找最佳值。我已經使用了類似大小的數據的sqlbulkcopy,它運行良好。

+0

謝謝,我添加了這個,並開始寫每100k記錄,我認爲我的問題是與文件讀取器對象,因爲我每次都在大約相同的地方用完內存 - 試圖找出我現在正在直接閱讀文件,怎樣才能保留我的位置... – 2010-08-02 07:21:08

+0

我仍然不認爲文件流是問題所在。你嘗試過大約1000的批量嗎?顯然在大約1000-2000個記錄中配料是最有效的。如果你確定它是文件,你可以做的是打開文件,讀取一千條記錄,存儲位置做一個批量插入,然後關閉文件。再次打開並將位置設置爲最後的位置並讀取另一批。 – 2010-08-02 10:52:22

+0

你一定是對的,因爲我在「try」塊中有實際的副本,並且出現了內存不足異常,所以它必須與try塊中的某些內容相關,否則我不會正確處理它。 我試着保存我的文件位置並報告結果。 – 2010-08-03 03:50:54

1

面對同樣的問題,發現OutOfMemory Exception的問題出現在DataTable.Rows最大數量限制中。 解決與重新創建表,最大500000行限制。 希望,我的解決方案將是有益的:

var myTable = new System.Data.DataTable(); 
myTable.Columns.Add("Guid", typeof(Guid)); 
myTable.Columns.Add("Name", typeof(string)); 

int counter = 0; 

foreach (var row in rows) 
{ 
    ++counter; 

    if (counter < 500000) 
    { 
     myTable.Rows.Add(
      new object[] 
      { 
       row.Value.Guid, 
       row.Value.Name 
      }); 
    } 
    else 
    { 
     using (var dbConnection = new SqlConnection("Source=localhost;...")) 
     { 
      dbConnection.Open(); 
      using (var s = new SqlBulkCopy(dbConnection)) 
      { 
       s.DestinationTableName = "MyTable"; 

       foreach (var column in myTable.Columns) 
        s.ColumnMappings.Add(column.ToString(), column.ToString()); 

       try 
       { 
        s.WriteToServer(myTable); 
       } 
       catch (Exception ex) 
       { 
        Console.WriteLine(ex.Message); 
       } 
       finally 
       { 
        s.Close(); 
       } 
      } 
     } 

     myTable = new System.Data.DataTable(); 
     myTable.Columns.Add("Guid", typeof(Guid)); 
     myTable.Columns.Add("Name", typeof(string)); 

     myTable.Rows.Add(
      new object[] 
      { 
       row.Value.Guid, 
       row.Value.Name 
      }); 

     counter = 0; 

    } 
}