2010-04-22 10 views
5

Sto cercando il modo più veloce per caricare i dati di massa tramite C#. Ho questo script che fa il lavoro ma lento. Leggo le testimonianze che SqlBulkCopy è il più veloce.
1000 record 2,5 secondi. i file contengono ovunque 5000 record a 250k Quali sono alcune delle cose che possono rallentarlo?SqlBulkCopy lento come melassa

Tabella Def:

CREATE TABLE [dbo].[tempDispositions](
    [QuotaGroup] [varchar](100) NULL, 
    [Country] [varchar](50) NULL, 
    [ServiceGroup] [varchar](50) NULL, 
    [Language] [varchar](50) NULL, 
    [ContactChannel] [varchar](10) NULL, 
    [TrackingID] [varchar](20) NULL, 
    [CaseClosedDate] [varchar](25) NULL, 
    [MSFTRep] [varchar](50) NULL, 
    [CustEmail] [varchar](100) NULL, 
    [CustPhone] [varchar](100) NULL, 
    [CustomerName] [nvarchar](100) NULL, 
    [ProductFamily] [varchar](35) NULL, 
    [ProductSubType] [varchar](255) NULL, 
    [CandidateReceivedDate] [varchar](25) NULL, 
    [SurveyMode] [varchar](1) NULL, 
    [SurveyWaveStartDate] [varchar](25) NULL, 
    [SurveyInvitationDate] [varchar](25) NULL, 
    [SurveyReminderDate] [varchar](25) NULL, 
    [SurveyCompleteDate] [varchar](25) NULL, 
    [OptOutDate] [varchar](25) NULL, 
    [SurveyWaveEndDate] [varchar](25) NULL, 
    [DispositionCode] [varchar](5) NULL, 
    [SurveyName] [varchar](20) NULL, 
    [SurveyVendor] [varchar](20) NULL, 
    [BusinessUnitName] [varchar](25) NULL, 
    [UploadId] [int] NULL, 
    [LineNumber] [int] NULL, 
    [BusinessUnitSubgroup] [varchar](25) NULL, 
    [FileDate] [datetime] NULL 
) ON [PRIMARY] 

ed ecco il codice

private void BulkLoadContent(DataTable dt) 
    { 
     OnMessage("Bulk loading records to temp table"); 
     OnSubMessage("Bulk Load Started"); 
     using (SqlBulkCopy bcp = new SqlBulkCopy(conn)) 
     { 
      bcp.DestinationTableName = "dbo.tempDispositions"; 
      bcp.BulkCopyTimeout = 0; 
      foreach (DataColumn dc in dt.Columns) 
      { 
       bcp.ColumnMappings.Add(dc.ColumnName, dc.ColumnName); 
      } 
      bcp.NotifyAfter = 2000; 
      bcp.SqlRowsCopied += new SqlRowsCopiedEventHandler(bcp_SqlRowsCopied); 
      bcp.WriteToServer(dt); 
      bcp.Close(); 
     } 
    } 
+1

lento rispetto a cosa? Quanti dischi? Quali altri approcci hai provato? È "lento" come in "gee, è meglio che prenda un caffè" o "potrei inserirlo a mano più velocemente di questo"? – GalacticCowboy

+0

Lenta come in "È meglio che prenda un caffè" 1000 dischi 2,5 secondi. i file contengono ovunque 5000 record a 250k –

+0

Il tuo db ha una funzione 'LOAD DATA INFILE' e puoi chiamarla direttamente? – dnagirl

risposta

1

cose che possono rallentare la copia di massa: indici di testo -Full sul tavolo -Triggers su Insert -Foreign-Key vincoli

3

Se si dispone di molti dati, l'impostazione del lotto su un numero ragionevolmente grande potrebbe essere utile:

bcp.BatchSize = 10000; 
0

L'implementazione IDataReader I sug stimato qui How to implement IDataReader? forse ti aiuta. L'ho usato con SqlBulkCopy come segue:

using (MyFileDataReader reader = new MyFileDataReader(@"C:\myfile.txt")) 
{ 
     SqlBulkCopy bulkCopy = new SqlBulkCopy(connection); 
     bulkCopy.DestinationTableName = "[my_table]"; 
     bulkCopy.BatchSize = 10000; 

     bulkCopy.WriteToServer(reader); 

     bulkCopy.Close(); 

} 
1

ho notato che il tentativo di svuotare grandi serie di dati è inizialmente molto più veloce, ma rallenta notevolmente nel corso del tempo. Ho riscontrato un modesto aumento delle prestazioni utilizzando un approccio tamponato, alimentando bulkcopy solo poche migliaia di dischi alla volta con la stessa connessione. Sembra che mantenga il tempo di transazione per-batch nel tempo, il che (nel tempo) migliora le prestazioni. Sulla mia soluzione, ho notato che lo stesso metodo senza buffer salverà circa 5.000.000 di record nel tempo impiegato da questo metodo per salvare circa 7.500.000 record dello stesso tipo nello stesso DB. Spero che questo aiuti qualcuno.

public void flush_DataTable(DataTable dt, string tableName)//my incoming DTs have a million or so each and slow down over time to nothing. This helps. 
    { int bufferSize = 10000; 
     int bufferHigh = bufferSize; 
     int lowBuffer = 0; 
     if (dt.Rows.Count >= bufferSize) 
     { using (SqlConnection conn = getConn()) 
      { conn.Open(); 
       while (bufferHigh < dt.Rows.Count) 
       { 
        using (SqlBulkCopy s = new SqlBulkCopy(conn)) 
        { s.BulkCopyTimeout = 900; 
         s.DestinationTableName = tableName; 
         s.BatchSize = bufferSize; 

         s.EnableStreaming = true; 
         foreach (var column in dt.Columns) 
          s.ColumnMappings.Add(column.ToString(), column.ToString()); 
         DataTable bufferedTable = dt.Clone(); 
         for (int bu = lowBuffer; bu < bufferHigh; bu++) 
         { 
          bufferedTable.ImportRow(dt.Rows[bu]); 
         } 
         s.WriteToServer(bufferedTable); 
         if (bufferHigh == dt.Rows.Count) 
         { 
          break; 
         } 
         lowBuffer = bufferHigh; 
         bufferHigh += bufferSize; 

         if (bufferHigh > dt.Rows.Count) 
         { 
          bufferHigh = dt.Rows.Count; 
         } 
        } 
       } 
       conn.Close(); 
      } 
     } 
     else 
     { 
      flushDataTable(dt, tableName);//perofrm a non-buffered flush (could just as easily flush the buffer here bu I already had the other method 
     } 
    } 
+0

Si potrebbe forse velocizzare le cose usando un Parallel. Per la copia della tabella e/o sfruttando il threading consentendo 2-3 inserimenti paralleli usando Attendere s.WriteToServerAsync. Si potrebbe anche provare a inserire la logica del ciclo (WHILE) all'interno del Using (s) e dopo il mapping della colonna in modo che tutto avvenga sotto la stessa istanza di SQLBulkCopy - Sono stato abbastanza soddisfatto con il 50% di aumento delle prestazioni nel tempo di questi altri trucchi. YMMV –

+1

Inoltre - questo è più lento quando una tabella è vuota - i guadagni di prestazioni sembrano venire via quando la tabella si riempie. Per alcuni milioni di dischi, dubito che ciò sarebbe di grande utilità. Ma per centinaia di milioni, mi ha risparmiato un sacco di tempo. –

Problemi correlati