2010-08-02 7 views
1

나는 복사하는 파일의 크기가 때때로 600MB를 초과하여 실행되기 때문에 SQLBULKCOPY를 사용하여 일부 데이터 테이블을 데이터베이스 테이블에 복사하고 있는데, 메모리가 부족한 상태로 유지됩니다.sqlbulkcopy mem. 관리

데이터베이스에 커밋하기 전에 테이블 크기 관리에 대한 조언을 받기를 바란다. 그래서 나는 계속 쓰기 위해 약간의 메모리를 비울 수있다. 여기

내 코드의 예 내가 SqlBulkCopy의 작동하도록 점점 문제가 계속

  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()); 

    } 

(편의상 제거 약간의 열과 행), 그리고 나는 더 많은 일을 작업 할 필요가 실현 각 레코드가 데이터베이스에 입력되기 전에 레코드 업데이트로 레코드를 수행하는 간단한 LinQ Sql 메서드를 개발하여 다른 정보를 편집하고 실행되는 동안 더 많은 레코드 정보를 만들 수 있습니다.

문제점 : 방법은 예쁜 slo를 달리고있다. w (코어 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(); 
        } 
       } 
      } 

:

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 폐기 좋은 생각을 –

+0

덕분에 수 있습니다 - 내가 전에 내 독자를 처분 만약 내가, 내가 궁금하네요 마음 에 그하겠습니다 나는 각 파일을 읽는 것을 끝내기 전에 독자를 끝내기 전에 내가 쓰는 동안 내가 읽지 않는 동안 내가 곧바로 읽고있는 동안 나는 나의 페이스를 느슨하게 할 것이고, 나는 메모리 오류를 가지고있다. 어떤 생각 내가 파일에 있던 곳으로 어떻게 뛰어 돌아갈 것인가? –

+0

위의 코멘트를 참조하십시오 ... –

답변

2

1000 BatchSize에서 속성을 지정하려고하는 것입니다 1000 기록 배치보다는 훨씬에 삽입까지 배치. 이 값을 조정하여 최적의 것을 찾을 수 있습니다. 유사한 크기의 데이터에 대해 sqlbulkcopy를 사용했으며 제대로 작동합니다.

+0

감사합니다, 나는 이것을 추가하고 모든 100k 레코드를 작성하기 시작했습니다. 매번 같은 장소에서 메모리가 부족하기 때문에 파일 판독기 개체에 문제가 있다고 생각합니다. 내가 지금 당장 똑바로 읽고있는 동안 파일에서 내 자리를 어떻게 유지할 수 있겠습니까? –

+0

필자는 파일 스트림이 문제라고 생각하지 않습니다. 약 1000 배칭 크기를 시도 했습니까? 분명히 약 1000-2000 기록에서 일괄 처리가 가장 효과적입니다. 파일이 확실하다면, 파일을 열고, 천개의 레코드를 읽고, 위치를 대량 삽입하여 저장 한 다음 파일을 닫는 것입니다. 그것을 다시 열고 마지막 위치로 위치를 설정하고 다른 배치를 읽으십시오. –

+0

"try"블록에 실제 복사본이 있고 메모리 부족 예외가 발생하므로 try 블록의 내용과 관련이 있어야합니다. 그렇지 않으면 올바르게 처리하지 못합니다. 파일 위치를 저장하고 결과를보고 해보십시오. –

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; 

    } 
} 
관련 문제