2011-11-06 14 views
7

He estado experimentando con formas de leer datos de un servidor SQL lo más rápido posible y encontré un descubrimiento interesante. Si leo los datos en un List<object[]> en lugar de un List<string[]>, el rendimiento aumenta en más del doble.SqlDataReader Lista de rendimiento <string[]> o Lista <object[]>

Sospecho que esto se debe a no tener que llamar al método ToString() en los campos, pero siempre pensé que el uso de objetos tenía un impacto negativo en el rendimiento.

¿Hay alguna razón para no usar una lista de matrices de objetos en lugar de matrices de cadenas?

EDIT: una idea que tuve fue el tamaño de almacenamiento de esta información. ¿Almacenar los datos en matrices de objetos requiere más espacio que cadenas?

Aquí está mi código de prueba:

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

Y los resultados:

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

No se puede discutir con los resultados. También debe envolver a sus lectores (y también a los comandos) en las instrucciones de uso, ya que pueden perder memoria. –

+0

Tiene que haber algún problema con la prueba ... En comparación con la lectura de los datos de la base de datos, hacer que el tipo de cadena revise * debe * ser insignificante. – Guffa

+0

Por curiosidad, ¿es diferente si simplemente convierte el valor del lector en una cadena ('row [i] = (string) reader [i];') en lugar de llamar 'ToString()' en él, o en su lugar, utilizando el método 'SqlDataReader.GetString()' incorporado para recuperar el valor ('row [i] = reader.GetString (i);')? (Asumiendo que todos los valores de columna son cadenas.) –

Respuesta

8

object solamente implica una sobrecarga si usted está causando boxeo adicional. E incluso entonces, este impacto es bastante mínimo. En su caso, reader[i]siempre devuelve object. Ya lo tiene como object, sin importar si es una referencia a una cadena, o un int, etc. De curso llamando al .ToString() agrega sobrecarga; en la mayoría de los casos (int, DateTime, etc.) esto implica tanto el código de formato y la asignación de una (o más) cadena adicional. Al cambiar a string está cambiando los datos (para peor, IMO - por ejemplo, ya no puede hacer géneros correctos en las fechas, por ejemplo) y agregar sobrecarga. El caso límite aquí es si todas las columnas ya son en realidad cadenas, en cuyo caso usted solo agrega algunas llamadas al método virtual (pero no hay trabajo real extra).

Para obtener más información, si busca el rendimiento en bruto, le recomiendo que mire los micro-ORM como, por ejemplo, apuesto. Están muy optimizados, pero evitan el peso de los ORM "completos". Por ejemplo, en el pulcro:

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

será, espero, realice muy comparable mientras que le da los datos de objetos con establecimiento inflexible.

+0

Marc, gracias por la buena información. En referencia a la solución micro-ORM, ¿esta solución no me exigiría conocer el conjunto de datos que estoy recuperando antes de ejecutar la consulta? Necesito que esta aplicación sea independiente de los datos que está recuperando – ChandlerPelhams

+0

@ChandlerPelhams que no estaba claro a partir de la pregunta; p Suponiendo que no se puede pasar un 'T' a través de genéricos (en la mayoría de las aplicaciones, * algunos * parte de la persona que llama sabe cómo se ven los datos), entonces, de hecho, algo más genérico, como 'object []' o, como notas "lowds '', DataTable', puede ser más apropiado. –

1

¿Hay alguna razón para no utilizar una lista de matrices de objetos en lugar de matrices de cadenas?

Dependerá de lo que quería hacer con los valores recuperados después de que los introdujo en las matrices, si está contento de tratar cada valor como un objeto, tener una lista de objetos está bien, pero si si quieres tratarlos como cadenas, en algún momento tendrás que convertir/convertir el objeto a una cadena, por lo que incurrirás en algún costo.

Como mencionó Cory si está leyendo el valor como una cadena del SqlDataReader, debe probar utilizando el método GetString (int) en lugar de llamar a ToString() sobre el valor, y usarlo como punto de referencia.

De forma alternativa, en lugar de utilizar matrices, puede leer los valores en un DataSet que puede resultar más fácil de utilizar posteriormente.

Al final del día, lo mejor depende en gran medida de cómo desea utilizar los resultados después de recuperarlos de la base de datos.

+0

lol, usabilidad de DataSet vs Lista de matrices ... creo que es un tema para otra pregunta SO :) – lowds

+0

@ Marc - Yo también :) – ChandlerPelhams

+0

En el caso dado, parece (comentarios) que el código puede no conocer el diseño , en cuyo caso debo señalar que DataTable puede ser apropiado. –

Cuestiones relacionadas