2011-02-01 12 views
5

tengo el siguiente (simplificado) código que me gustaría optimizar la velocidad:C# Optimización: Inserción de 200 millones de filas en la base de datos

long inputLen = 50000000; // 50 million 
DataTable dataTable = new DataTable(); 
DataRow dataRow; 
object[] objectRow; 
while (inputLen--) 
{ 
    objectRow[0] = ... 
    objectRow[1] = ... 
    objectRow[2] = ... 

    // Generate output for this input 
    output = ... 

    for (int i = 0; i < outputLen; i++) // outputLen can range from 1 to 20,000 
    { 
     objectRow[3] = output[i]; 
     dataRow = dataTable.NewRow(); 
     dataRow.ItemArray = objectRow; 
     dataTable.Rows.Add(dataRow); 
    } 
} 

// Bulk copy 
SqlBulkCopy bulkTask = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, null); 
bulkTask.DestinationTableName = "newTable"; 
bulkTask.BatchSize = dataTable.Rows.Count; 
bulkTask.WriteToServer(dataTable); 
bulkTask.Close(); 

ya estoy usando SqlBulkCopy en un intento de acelerar las cosas , pero parece que la asignación de valores a la DataTable en sí misma es lenta.

No sé cómo funcionan las DataTables, así que me pregunto si estoy creando sobrecarga innecesaria creando primero una matriz reutilizable, luego asignándola a una DataRow, y luego agregando DataRow a la DataTable. ¿O está utilizando DataTable no es óptimo en primer lugar? La entrada proviene de una base de datos.

No me importa mucho la LOC, solo la velocidad. ¿Alguien puede dar un consejo sobre esto?

+0

Para ver una implementación de ejemplo, consulte 'SimpleDataReader' [aquí] (https://groups.google.com/group/microsoft.public.dotnet.languages.csharp/msg/b1d70b504cdee2ad?hl=en) –

Respuesta

13

Para una gran mesa tales, en su lugar debe utilizar el método

public void WriteToServer(IDataReader reader) 

.

Puede significar que tendrá que implementar una interfaz "falsa" IDataReader con su código (si no obtiene los datos de un IDataReader existente), pero de esta manera, obtendrá "transmisión" de extremo a extremo, y evitará un bucle de 200 millones.

+1

Supongo que me lo ganaste :) –

+0

¿Eso significa que SQLBulkCopy aún puede escribir de manera eficiente en la base de datos ** como ** las filas se están construyendo? ? La entrada proviene de la misma base de datos, pero para cada fila estoy creando potencialmente 20000 nuevas. –

+0

@ Box9 sí, exactamente eso –

0

No debe construir toda la tabla de datos en la memoria. Utilice este overload de WrtieToServer, que toma una matriz de DataRow. Solo divide en pedazos tus datos.

+0

Isn ' ¿Ese método todavía lo está construyendo en la memoria? Y además, si no me estoy quedando sin memoria, ¿no está construyéndola en memoria más rápido? –

+0

si construye solo 1k filas a la vez en vez de 200m, sería mucho más fácil para el administrador de memoria mantener dicha cantidad de datos. además de esto, es casi seguro que obtienes un intercambio con 200m de registros retenidos en la memoria al mismo tiempo – gor

4

En lugar de tener una gran tabla de datos en la memoria, sugiero implementar un IDataReader que sirve los datos como va la copia masiva. Esto reducirá la necesidad de mantener todo en la memoria por adelantado, y por lo tanto, debe servir para mejorar el rendimiento.

Cuestiones relacionadas