2014-12-16 10 views
5

Vogliamo trasferire un'enorme quantità di dati tra Oracle 11g R2 & SQL Server 2014 in un po 'di tempo ... stiamo parlando di 20+ Tb, migliaia di tavoli, e miliardi di record (si tratta di un Datawarehouse 5 anni)Multithread Data Transfer tra Oracle e SQL Server - Network Performance

SSIS non è un'opzione, perché la quantità di tavoli & partizioni abbiamo bisogno di trasferire è enorme, circa 40k tavoli & partizioni .. abbiamo un po 'di marketing Apps, Gestori delle campagne, modelli di data mining e altri, che eseguono schemi diversi ... alcuni di essi creano circa 150 nuovi tavoli ogni giorno e la "percentuale di drop table" è di circa 100 al giorno ... alcune di queste tabelle hanno indici, altre no. .. questi schemi sono la ragione il motivo per cui non possiamo semplicemente usare SSIS, perché abbiamo bisogno di trasferire anche loro ... Modifica per includere ulteriori informazioni sul perché SSIS non sembra un'opzione praticabile

Così abbiamo sviluppato un'applicazione in C# 2013, con .Net 4.5.1, ed è multithreading ... ogni thread legge una tabella/partizione in oracle, crea lo stesso schema tabella/partizione in sql server, e procede a selezionare i dati in oracle, e bulk inserito in sql server, e infine, crea ogni vincolo e indice in sospeso ...

Uno dei problemi principali che stiamo affrontando è la velocità di trasferimento ... Confronto tra prestazioni SSIS trasferimento di 1 tabella dei fatti con 30 partizioni (fatto mensile, partizione giornaliera, circa 30 milioni di righe per partizione, 60 + colonne) contro la nostra app C#, abbiamo riscontrato che l'app non utilizza mai la piena velocità di rete mentre SSIS utilizza il 100% (usiamo i connettori SSIS Attunity per Oracle ... e probabilmente uno dei vantaggi del trasferimento di velocità è qui, non lo so), e vogliamo migliorare questo se possiamo ...

questo è il blocco di codice responsabile della scrittura

//private static async Task saveDataBlock(IDataReader reader, string destinationTable, int batchSize) 
private static void saveDataBlock(IDataReader reader, string destinationTable, int batchSize) 
{ 
    //System.Data.SqlClient.SqlBulkCopy bc = new System.Data.SqlClient.SqlBulkCopy(getConnString(destinationCS)); 
    //System.Data.SqlClient.SqlBulkCopy bc = new System.Data.SqlClient.SqlBulkCopy(getConnString(destinationCS), System.Data.SqlClient.SqlBulkCopyOptions.KeepIdentity & System.Data.SqlClient.SqlBulkCopyOptions.KeepNulls & System.Data.SqlClient.SqlBulkCopyOptions.TableLock); 
    using (SqlBulkCopy bc = new SqlBulkCopy(getConnString(destinationCS))) 
    { 
     bc.BulkCopyTimeout = 0; 
     bc.DestinationTableName = destinationTable; 
     bc.BatchSize = batchSize; //2500,5000,10000.. best so far, 5000 
     //bc.BatchSize = 0; 
     bc.NotifyAfter = batchSize; 
     bc.SqlRowsCopied += new SqlRowsCopiedEventHandler(s_SqlRowsCopied); 
     //bc.EnableStreaming = true;    

     bc.ColumnMappings.Clear(); 
     for (int i = 0; i < reader.FieldCount; i++) 
     { 
      bc.ColumnMappings.Add(reader.GetName(i), reader.GetName(i)); 
     } 

     bc.WriteToServer(reader); 
     //await bc.WriteToServerAsync(reader); 
     //bc.Close(); 
    } 

    //System.Data.SqlClient.SqlBulkCopy bc = new System.Data.SqlClient.SqlBulkCopy(getConnString(destinationCS), SqlBulkCopyOptions.UseInternalTransaction);    

} 

Qualcuno ha qualche suggerimento su una qualsiasi opzione possiamo testare dei configure (sezioni commentate di il codice proviene da precedenti opzioni testate), in SQL Server o nell'oggetto SQLBulkCopy nell'app C#?

PS: alcune informazioni sul nostro ambiente ... Oracle Server Client Uplink 2 Gbps, SQL Server Downlink 1 Gbps, Oracle è un sistema 32 core, il nostro test SQL Server è un sistema 16 Server Win Server 2012 R2. . SSIS velocità di trasferimento netto è di 1 Gbps full, C# App velocità di trasferimento netto è di circa 70 Mbps, con 16 thread ...

Modifica per portare più informazioni circa la velocità di trasferimento

maggiori informazioni sulla nostra app test:

2 thread = 15-25 Mbps

4 fili = 30-40 Mbps

8 thread = 60-65 Mbps

16 thread = 65-70 Mbps

Tutto quanto sopra 16 (1 filetto app per core system) abbattere le prestazioni a 30-50 Mbps ..

nostra SAN è molto capace di velocità superiori a 500 MB/s, ad un conteggio ad alta I/O

nostri migliori tempi di dimensione del lotto che abbiamo ottenuto con valori compresi tra 2500-5000 righe per batch (circa 15 milioni di righe in 5 minuti, con 8-16 thread)

In questo momento la nostra app trasferisce i dati da una tabella/partizione in Oracle a un'altra in SQL Server ... abbiamo alcune tabelle non partizionate con oltre 100 milioni di righe ... per in questa tabella abbiamo testato più thread leggendo la stessa tabella ... abbiamo avuto successo nel processo di lettura, ma fallito nell'insieme di dati di massa

ead legge la stessa tabella di fare un'operazione MOD su una colonna numerica ...

select * from schema.table where MOD(NUMERIC_COLUMN, N) = 0 to N-1 

N è il numero di thread che corriamo ... Abbiamo cercato di ricreare alcuni comportamenti SSIS per massimizzare l'uso filo & lettura dei dati/scrivere in Oracle/SQL .. In SSIS possiamo impostare ogni thread con l'opzione LOCK TABLE a destinazione, e ha funzionato in modo impeccabile .. ma mentre lo facciamo nella nostra app, ogni thread blocca la tabella durante l'inserimento, e infine il nostro design in parallelo corre serializzato :((Questo non è il motivo principale della domanda, ma se qualcuno ha suggerimenti su questo, sarà apprezzato)

+0

Quando si esegue SSIS e l'app C#, si notano differenze nei tipi/tempi di attesa per le scritture su SQL? –

+1

Per curiosità perversa, potresti aiutarmi a capire che 'SSIS non è un'opzione, perché la quantità di tabelle e partizioni che dobbiamo trasferire è enorme? Sembra che gestisca la velocità proprio bene rispetto al tuo sistema homegrown – billinkc

+1

quindi quanti fili stai creando? Avere molti thread in esecuzione simultaneamente sarà un grande successo. Mostra altro codice. –

risposta

0

Non sei lontano dal throughput massimo teorico su un 1Gbps collegamento. Il throughput massimo di 1 Gbps è di 125 MB/s SENZA sovraccarico. Stai davvero guardando a 90 MB/s effettivi e se stai passando attraverso uno switch, un router o un firewall di livello 3 che sta elaborando i pacchetti, il throughput diminuirà. La soluzione migliore è quella di ottenere i server sullo stesso segmento di rete e ottenere un collegamento più veloce tra loro. Sospetto che il tuo throughput stia diminuendo quando il conteggio dei thread è più alto perché i thread stanno combattendo per l'accesso alla NIC (o la NIC sta introducendo un ritardo per pacchetto a causa della grande dimensione del pacchetto) e i thread stanno avendo l'esecuzione della pausa (dormi) e riprova.

Penso che il tuo problema sia il throughput. Prova una connessione a velocità più elevata collegando due collegamenti da 1 Gbps. Oppure, se i server sono vicini tra loro, collegarli direttamente (senza interruttore) utilizzando un cavo incrociato per verificare se le velocità di trasferimento aumentano. Se lo fanno, sai che hai un problema di throughput. Se non lo fanno, hai almeno eliminato una possibilità.