2010-05-31 13 views
6

Tengo el siguiente método para insertar millones de filas de datos en una tabla (uso SQL 2008) y parece lento, ¿hay alguna manera de acelerar INSERT?speed up sql INSERTs

Aquí es el fragmento de código - Yo uso la biblioteca de la empresa MS

 public void InsertHistoricData(List<DataRow> dataRowList) 
     { 
      string sql = string.Format(@"INSERT INTO [MyTable] ([Date],[Open],[High],[Low],[Close],[Volumn]) 
       VALUES(@DateVal, @OpenVal, @High, @Low, @CloseVal, @Volumn)"); 

      DbCommand dbCommand = VictoriaDB.GetSqlStringCommand(sql); 
      DB.AddInParameter(dbCommand, "DateVal", DbType.Date); 
      DB.AddInParameter(dbCommand, "OpenVal", DbType.Currency); 
      DB.AddInParameter(dbCommand, "High", DbType.Currency); 
      DB.AddInParameter(dbCommand, "Low", DbType.Currency); 
      DB.AddInParameter(dbCommand, "CloseVal", DbType.Currency); 
      DB.AddInParameter(dbCommand, "Volumn", DbType.Int32); 

      foreach (NasdaqHistoricDataRow dataRow in dataRowList) 
      { 
       DB.SetParameterValue(dbCommand, "DateVal", dataRow.Date); 
       DB.SetParameterValue(dbCommand, "OpenVal", dataRow.Open); 
       DB.SetParameterValue(dbCommand, "High", dataRow.High); 
       DB.SetParameterValue(dbCommand, "Low", dataRow.Low); 
       DB.SetParameterValue(dbCommand, "CloseVal", dataRow.Close); 
       DB.SetParameterValue(dbCommand, "Volumn", dataRow.Volumn); 

       DB.ExecuteNonQuery(dbCommand); 
      } 
     } 
+0

¿Se insertan estos datos mientras que las actividades SELECT pueden ser simultáneas? –

+0

No, yo soy el único usuario para ese db. – sean717

+0

En ese caso, el consejo sobre este hilo http://stackoverflow.com/questions/751039/slow-bulk-insert-for-table-with-many-indexes sobre deshabilitar índices podría ser beneficioso. –

Respuesta

10

considerar el uso de bulk insert lugar.

SqlBulkCopy le permite a granel eficiente carga una tabla de SQL Server con los datos de otra fuente. La clase SqlBulkCopy se puede utilizar para escribir datos solo en SQL Tablas de servidor. Sin embargo, la fuente de datos no está limitada a SQL Server; se puede utilizar cualquier fuente de datos, como como los datos pueden cargarse en una instancia de DataTable o leer con una instancia de IDataReader . Para este ejemplo , el archivo contendrá aproximadamente 1000 registros , pero este código puede manejar grandes cantidades de datos.

Este ejemplo crea primero un DataTable y lo rellena con los datos. Esto se guarda en la memoria.

DataTable dt = new DataTable(); 
string line = null; 
bool firstRow = true; 

using (StreamReader sr = File.OpenText(@"c:\temp\table1.csv")) 
{ 
     while ((line = sr.ReadLine()) != null) 
     { 
      string[] data = line.Split(','); 
      if (data.Length > 0) 
      { 
        if (firstRow) 
        { 
         foreach (var item in data) 
         { 
           dt.Columns.Add(new DataColumn()); 
         } 
         firstRow = false; 
        } 

        DataRow row = dt.NewRow(); 
        row.ItemArray = data; 
        dt.Rows.Add(row); 
      } 
     } 
} 

Luego empujamos el DataTable al servidor de una sola vez.

using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConsoleApplication3.Properties.Settings.daasConnectionString"].ConnectionString)) 
{ 
     cn.Open(); 
     using (SqlBulkCopy copy = new SqlBulkCopy(cn)) 
     { 
      copy.ColumnMappings.Add(0, 0); 
      copy.ColumnMappings.Add(1, 1); 
      copy.ColumnMappings.Add(2, 2); 
      copy.ColumnMappings.Add(3, 3); 
      copy.ColumnMappings.Add(4, 4); 
      copy.DestinationTableName = "Censis"; 
      copy.WriteToServer(dt); 
     } 
} 
+0

es definitivamente la mejor opción aquí ya que el asker de preguntas ya tiene una secuencia de lectores de datos, estos pueden pasarse a una copia masiva sql ... –

+0

intenté esto y funcionó, thx – sean717

+0

+1 y quería decir gracias, tomó Solo necesito un momento para adaptar su código de muestra a mi propia solución, reduciendo mi dilema de rendimiento de CSV a SQL de 30 segundos a menos de un segundo ahora. (No es gran cosa, pero también quería señalar una llave de tuerca no coincidente en su muestra anterior, donde está comprobando si 'i == 0' para construir las columnas). – Funka

0

¿De dónde provienen los datos? ¿Podría ejecutar una inserción masiva? Si es así, esa es la mejor opción que puede tomar.

1

Un consejo general sobre cualquier base de datos relacional cuando se hace una gran cantidad de insertos, o incluso cualquier cambio de datos, es soltar primero todos sus índices secundarios y luego recrearlos posteriormente.

¿Por qué funciona esto? Bien con los índices secundarios, los datos del índice estarán en otro lugar del disco que los datos, forzando a lo mejor una actualización adicional de lectura/escritura para cada registro escrito en la tabla por índice. De hecho, puede ser mucho peor que esto, ya que de vez en cuando la base de datos decidirá que necesita llevar a cabo una operación de reorganización más seria en el índice.

Al volver a crear el índice al final de la ejecución de la inserción, la base de datos realizará solo una exploración completa de la tabla para leer y procesar los datos. No solo terminará con un mejor índice organizado en el disco, sino que la cantidad total de trabajo requerido será menor.

¿Cuándo vale la pena hacerlo? Eso depende de su base de datos, estructura de índice y otros factores (como si tiene sus índices en un disco separado para sus datos) pero mi regla de oro es considerarlo si estoy procesando más del 10% de los registros en una tabla de un millón de registros o más, y luego verifique con inserciones de prueba para ver si vale la pena.

Por supuesto, en cualquier base de datos particular habrá rutinas de inserción a granel de especialista, y también debe mirar esas.

1

FYI - realizar un bucle a través de un conjunto de registros y hacer un millón de inserciones en una base de datos relacional es el peor de los casos al cargar una tabla. Algunos idiomas ahora ofrecen objetos de conjunto de registros. Para un rendimiento más rápido SMINK es correcto, use BULK INSERT. Millones de filas cargadas en minutos, en lugar de horas. Órdenes de magnitud más rápido que cualquier otro método.

Como ejemplo, trabajé en un proyecto de comercio electrónico, que requería una actualización de la lista de productos cada noche. 100,000 filas insertadas en un Oracle DB de alta gama, tomaron 10 horas. Si mal no recuerdo, la velocidad máxima a la hora de hacer las inserciones fila por fila es de aproximadamente 10 recs/seg. Doloroso lento y completamente innecesario. Con la inserción en bloque, las filas de 100K deberían tardar menos de un minuto.

Espero que esto ayude.