2011-11-06 1 views
7

가능한 빨리 SQL 서버에서 데이터를 읽는 방법을 실험 해본 결과 흥미로운 발견이 나타났습니다. List<string[]> 대신 List<object[]>으로 데이터를 읽으면 성능이 두 배 이상 향상됩니다.SqlDataReader 성능 목록 <string[]> 또는 목록 <object[]>

이것은 필드에 ToString() 메서드를 호출 할 필요가 없기 때문에 의심 스럽지만 항상 개체를 사용하면 성능에 부정적인 영향을 줄 것이라고 생각했습니다.

문자열 배열 대신 개체 배열 목록을 사용하지 않는 이유가 있습니까?

편집 : 방금 한 가지 생각은이 데이터의 저장 크기입니다. 객체 배열에 데이터를 저장하는 것이 문자열보다 많은 공간을 차지합니까?

private void executeSqlObject() 
    { 
     List<object[]> list = new List<object[]>(); 

     using (SqlConnection cnn = new SqlConnection(_cnnString)) 
     { 
      cnn.Open(); 
      SqlCommand cmd = new SqlCommand("select * from test_table", cnn); 

      SqlDataReader reader = cmd.ExecuteReader(); 

      int fieldCount = reader.FieldCount; 

      while (reader.Read()) 
      { 
       object[] row = new object[fieldCount]; 

       for (int i = 0; i < fieldCount; i++) 
       { 
        row[i] = reader[i]; 
       } 
       list.Add(row); 
      } 
     } 
    } 

    private void executeSqlString() 
    { 
     List<string[]> list = new List<string[]>(); 

     using (SqlConnection cnn = new SqlConnection(_cnnString)) 
     { 
      cnn.Open(); 
      SqlCommand cmd = new SqlCommand("select * from test_table", cnn); 

      SqlDataReader reader = cmd.ExecuteReader(); 

      int fieldCount = reader.FieldCount; 

      while (reader.Read()) 
      { 
       string[] row = new string[fieldCount]; 

       for (int i = 0; i < fieldCount; i++) 
       { 
        row[i] = reader[i].ToString(); 
       } 
       list.Add(row); 
      } 
     } 
    } 

    private void runTests() 
    { 
     Stopwatch watch = new Stopwatch(); 
     for (int i = 0; i < 10; i++) 
     { 
      watch.Start(); 
      executeSqlObject(); 
      Debug.WriteLine("Object Time: " + watch.ElapsedMilliseconds.ToString()); 
      watch.Reset(); 
     } 
     for (int i = 0; i < 10; i++) 
     { 
      watch.Start(); 
      executeSqlString(); 
      Debug.WriteLine("String Time: " + watch.ElapsedMilliseconds.ToString()); 
      watch.Reset(); 
     } 
    } 

결과 : 당신이 추가 권투를 일으키는 경우

Object Time: 879 
Object Time: 812 
Object Time: 825 
Object Time: 882 
Object Time: 880 
Object Time: 905 
Object Time: 815 
Object Time: 799 
Object Time: 823 
Object Time: 817 
Average: 844 

String Time: 1819 
String Time: 1790 
String Time: 1787 
String Time: 1856 
String Time: 1795 
String Time: 1731 
String Time: 1792 
String Time: 1799 
String Time: 1762 
String Time: 1869 
Average: 1800 
+1

결과를 주장 할 수 없습니다. 또한 메모리를 누출시킬 수 있기 때문에 명령문을 사용하여 독자와 명령을 래핑해야합니다. –

+0

테스트에 문제가있을 수 있습니다 ... 데이터베이스에서 데이터를 읽는 것과 비교하여 문자열 유형 검사 *를 잘못 수행해야합니다. – Guffa

+0

호기심 때문에 독자가 단순히 ToString()을 호출하는 대신 독자 값을 문자열 ('row [i] = (string) reader [i];)에 캐스팅하거나, 내장'SqlDataReader.GetString()'메서드를 사용하여 값을 검색합니다 ('row [i] = reader.GetString (i);)? (모든 열 값은 문자열입니다.) –

답변

8

object는 오버 헤드가 추가

여기 내 테스트 코드입니다. 그리고 그때조차도,이 영향은 아주 적습니다. 귀하의 경우 reader[i]항상object을 반환합니다. 문자가 object인지 여부와 관계없이 문자열이나 int 등이 있는지 여부와 관계없이 .ToString()을 호출하면 오버 헤드가 추가됩니다. 대부분의 경우 (int, DateTime 등)이 코드에는 의 형식 지정 코드 둘 모두에 하나 이상의 (또는 그 이상의) 추가 문자열이 할당됩니다. string으로 변경하면 데이터를 변경하는 입니다 (예 : 더 이상 IMO가 아닙니다. 예를 들어 더 이상 정확한 날짜 정렬을 수행 할 수 없음). 오버 헤드를 추가합니다. 여기의 엣지 경우는 모든 열이 이미 실제 문자열 인 경우입니다.이 경우 몇 가지 가상 메서드 호출을 추가하기 만합니다 (그러나 추가 실제 작업은 필요 없습니다).

원시 퍼포먼스 후인 경우, dapper와 같은 마이크로 ORM을 살펴 보는 것이 좋습니다. 그들은 많이 최적화되어 있지만 "전체"ORM의 무게는 피하십시오. 날씬한 예, 들어 : 당신에게 강력한 형식의 객체 데이터를 제공하면서

var myData = connection.Query<TypedObject>("select * from test_table").ToList(); 

, 내가 기대, 매우 비교적 수행합니다.

+0

마크와 비교하여 어떤 결과가 있었습니까? 좋은 정보를 주셔서 감사합니다. 마이크로 -ORM 솔루션과 관련하여이 솔루션을 사용하면 쿼리를 실행하기 전에 검색하는 데이터 집합을 알 필요가 없습니까? 이 응용 프로그램을 검색하는 데이터에 대해 알 필요가 없습니다 – ChandlerPelhams

+0

질문에서 명확하지 않은 @ChandlerPelhams; p 제네릭을 통해 'T'를 전달할 수 없다고 가정합니다 (대부분의 응용 프로그램에서는 호출자의 일부 * 일부). 데이터가 어떻게 보이는지), 실제로'object [] '나'lowds '노트 인'DataTable' 같은 좀 더 일반적인 것이 더 적절할 수 있습니다. –

1

문자열 배열 대신 개체 배열 목록을 사용하지 않는 이유가 있습니까?

그것은 당신이 배열로있어 후 미세 당신이 다음 개체의 목록을 갖는 개체로 각 값을 치료하는 행복 경우, 검색된 값으로하고 싶었던 무엇에 따라 달라

하지만 경우 당신은 그들을 문자열로 취급하고 싶다면 어떤 시점에서 객체를 문자열로 변환/캐스트해야하므로 어딘가에서 비용이 발생하게됩니다.

Cory는 SqlDataReader에서 값을 문자열로 읽는 경우 값에 ToString()을 호출하는 대신 GetString (int) 메서드를 사용하여 테스트하고이를 벤치 마크로 사용해야합니다.

또는 배열을 사용하지 않고 값을 데이터 세트로 읽어 들일 수 있습니다.이 값은 나중에 작업하기가 더 쉬울 수도 있습니다.

마지막 일은 최선의 결과가 데이터베이스에서 검색 한 후 결과를 사용하는 방법에 달려 있습니다.

+0

lol, 데이터 집합 대 배열의 유용성 ... 다른 SO 질문에 대한 주제라고 생각하십시오 :) – lowds

+0

@ Marc - Me : – ChandlerPelhams

+0

주어진 경우, 코드가 레이아웃을 알지 못하는 것 같습니다 (의견) 이 경우 DataTable이 실제로 적합 할 수 있음에 유의해야합니다. –