2012-05-24 2 views
1

for 루프를 사용하여 약 40 000 개의 레코드가 포함 된 데이터 테이블을 반복하는 데는 거의 4 분이 걸립니다. 루프 내에서는 각 행의 특정 열 값을 읽고 문자열에 concatinating하는 것입니다.C# : 거대한 데이터 테이블을 반복합니다.

DB 연결이나 다른 것을 열지 않습니다. 데이터 테이블을 수신하고 반복하며 문자열을 반환하는 함수입니다.

더 빠른 방법이 있습니까?

코드는 여기에 표시됩니다 :

private string getListOfFileNames(Datatable listWithFileNames) 
    {  
     string whereClause = ""; 

      if (listWithFileNames.Columns.Contains("Filename")) 
      { 
       whereClause = "where filename in ("; 
       for (int j = 0; j < listWithFileNames.Rows.Count; j++) 
        whereClause += " '" + listWithFileNames.Rows[j]["Filename"].ToString() + "',"; 
      } 
      whereClause = whereClause.Remove(whereClause.Length - 1, 1); 
      whereClause += ")";  

     return whereClause;     
    }  
+6

일부 코드 게시 –

+0

데이터 테이블에 'LINQ'를 사용해 보셨습니까? – Luis

+0

일부 코드를 보거나이 코드에 대한 자세한 설명을 제공하는 것이 좋습니다. 예를 들어, StringBuilder 클래스를 사용하여 대부분의 시간을 차지할 수있는 문자열 만 연결할 수 있습니다. –

답변

0

다음 LINQ 문을 가지고 어디에 첫 번째 열에서와 변수에 세 번째 열 CONCAT 절.

string CSVValues = String.Join(",", dtOutput.AsEnumerable() 
               .Where(a => a[0].ToString() == value) 
               .Select(b => b[2].ToString())); 
2
  1. 그냥 일반 문자열 연결 대신 문자열을 CONCAT하기 위해 모두 StringBuilder를 사용하고 있습니까?
  2. 데이터베이스에서 더 이상 열을 가져 와서 정말로 필요합니까? 그렇다면 그렇게하지 마십시오. 필요한 컬럼 만 되돌립니다.
  3. 데이터베이스에서 더 이상 행을 가져 와서 정말로 필요합니까? 그렇다면 그렇게하지 마십시오. 필요한 행만 뒤로 당깁니다.
  4. 컴퓨터의 메모리 용량은 얼마입니까? 프로그램을 실행하거나 프로그램에 접근 할 때 최대 효과가 있습니까? 프로세서가 최대 또는 최대입니까? 너가 너무 많은 기억을 사용하면 너는 더 스트리밍을 할 필요가 있을지도 모른다. 이는 전체 결과 세트를 메모리 (즉, 데이터 테이블)로 가져 오지 않고 각 라인을 한 번에 하나씩 읽는 것을 의미합니다. 또한 결과를 문자열 (또는 StringBuilder)로 연결하지 않고 파일에 추가하여 메모리를 많이 차지하지 않도록 할 수도 있습니다.
+0

코드 추가 .... 예, 일반 문자열을 사용하고 있습니다. – sunsa428

0

1 단계 - 프로파일 러를 통해 실행하고, 최적화 할 때 올바른 것을보고 있는지 확인하십시오.

사례를 살펴보면 데이터베이스 상호 작용이 느린 문제가 발생했으며 프로파일 러를 실행했을 때 db가 거의 나타나지 않았습니다. 말했다

가능한 상황이 시도 : 당신이 메모리를 사용할 수있는 경우

  • 이 전체 DB를 읽기를 강제로, 목록에 쿼리를 변환합니다. 그렇지 않으면 linq는 아마 복수의 db 쿼리를 수행하는 청크에서로드 될 것입니다.
  • 는 DB에 일을 밀어 - 당신이 뭔가 어디 인 경우 빠른
  • 이 될 수 있습니다 당신도보고되거나 데이터가 당신을 위해 문자열을 계산 아래 트림보다 쿼리, 을 만들 수있는 경우 쿼리 자주 실행되지만 데이터가 거의 으로 변경되면원격 db를 사용하는 경우 데이터를 로컬 db (예 : sqlite)로 복사하는 것이 좋습니다.
  • 로컬 sql-server를 사용하는 경우 sqlite를 실행하면 은 더 빠릅니다. 식으로 테이블에 더미 열을 추가
0
var value = dataTable 
      .AsEnumerable() 
      .Select(row => row.Field<string>("columnName")); 

var colValueStr = string.join(",", value.ToArray()); 
+0

코드를 추가했습니다 .... – sunsa428

+0

더 좋습니까? – zbugs

0

보십시오.다음과 같이 입력하십시오 :

DataColumn dynColumn = new DataColumn(); 

{ 
    dynColumn.ColumnName = "FullName"; 
    dynColumn.DataType = System.Type.GetType("System.String"); 
    dynColumn.Expression = "LastName+' '-ABC"; 
} 
UserDataSet.Tables(0).Columns.Add(dynColumn); 

나중에이 더미 열을 대신 사용할 수 있습니다. 문자열을 연결하기 위해 루프를 회전 할 필요가 없습니다.

0

루프 병렬를 사용해보십시오 .. 는 여기에 내가 작은 조각에서 일을 분리 한

Parallel.ForEach(dataTable.AsEnumerable(), 
      item => { str += ((item as DataRow)["ColumnName"]).ToString(); }); 
0

.. 샘플 코드의 각 조각이 자신의 스레드에 의해 처리 될 수 있습니다. nthreads 수를 변경하여 스레드 수를 미세 조정할 수 있습니다. 다른 숫자로 시도해보십시오. 그러면 성능 차이를 볼 수 있습니다.

private string getListOfFileNames(DataTable listWithFileNames) 
{ 
    string whereClause = String.Empty; 

    if (listWithFileNames.Columns.Contains("Filename")) 
    { 
     int nthreads = 8; // You can play with this parameter to fine tune and get your best time. 
     int load = listWithFileNames.Rows.Count/nthreads; // This will tell how many items reach thread mush process. 

     List<ManualResetEvent> mres = new List<ManualResetEvent>(); // This guys will help the method to know when the work is done. 
     List<StringBuilder> sbuilders = new List<StringBuilder>(); // This will be used to concatenate each bis string. 

     for (int i = 0; i < nthreads; i++) 
     { 
      sbuilders.Add(new StringBuilder()); // Create a new string builder 
      mres.Add(new ManualResetEvent(false)); // Create a not singaled ManualResetEvent. 

      if (i == 0) // We know were to put the very begining of your where clause 
      { 
       sbuilders[0].Append("where filename in ("); 
      } 

      // Calculate the last item to be processed by the current thread 
      int end = i == (nthreads - 1) ? listWithFileNames.Rows.Count : i * load + load; 

      // Create a new thread to deal with a part of the big table. 
      Thread t = new Thread(new ParameterizedThreadStart((x) => 
      { 
       // This is the inside of the thread, we must unbox the parameters 
       object[] vars = x as object[]; 
       int lIndex = (int)vars[0]; 
       int uIndex = (int)vars[1]; 
       ManualResetEvent ev = vars[2] as ManualResetEvent; 
       StringBuilder sb = vars[3] as StringBuilder; 
       bool coma = false; 

       // Concatenate the rows in the string builder 
       for (int j = lIndex; j < uIndex; j++) 
       { 
        if (coma) 
        { 
         sb.Append(", "); 
        } 
        else 
        { 
         coma = true; 
        } 

        sb.Append("'").Append(listWithFileNames.Rows[j]["Filename"]).Append("'"); 
       } 

       // Tell the parent Thread that your job is done. 
       ev.Set(); 
      })); 

      // Start the thread with the calculated params 
      t.Start(new object[] { i * load, end, mres[i], sbuilders[i] }); 
     } 

     // Wait for all child threads to finish their job 
     WaitHandle.WaitAll(mres.ToArray()); 

     // Concatenate the big string. 
     for (int i = 1; i < nthreads; i++) 
     { 
      sbuilders[0].Append(", ").Append(sbuilders[i]); 
     } 

     sbuilders[0].Append(")"); // Close your where clause 

     // Return the finished where clause 
     return sbuilders[0].ToString(); 
    } 

    // Returns empty 
    return whereClause; 
} 
+0

내 코드를보고 ..... 작성한 코드를 설명 할 수 있습니까? – sunsa428

+0

@ sunsa428 예, 코드가 수행중인 작업을 수행하도록 코드를 수정했습니다. 복사/붙여 넣기/시도 만하면됩니다. 나는 멀티 스레딩을 사용하여 더 빠른 시간에 작업을 완료하고 문자열 빌더를 사용하여 문자열을 연결합니다. 문자열을 문자열과 연결하는 것보다 훨씬 빠릅니다. –

관련 문제