2011-09-08 13 views
15

Ho bisogno di consumare grandi quantità di dati da un file CSV giornaliero. Il CSV contiene circa 120K di record. Questo sta rallentando a una scansione quando si utilizza la sospensione. Fondamentalmente, sembra che l'ibernazione stia facendo una SELECT prima di ogni singolo INSERT (o UPDATE) quando si usa saveOrUpdate(); per ogni istanza che viene mantenuta con saveOrUpdate(), viene emesso un SELECT prima dell'INSERTO effettivo o di un UPDATE. Posso capire perché sta facendo questo, ma è terribilmente inefficiente per eseguire l'elaborazione di massa, e sto cercando alternativeInserimento di massa O aggiornamento con ibernazione?

Sono fiducioso che il problema di prestazioni sta nel modo in cui sto usando l'ibernazione per questo, dato che Ho un'altra versione che funziona con SQL nativo (che analizza il CSV nello stesso modo) e circonda letteralmente i cerchi attorno a questa nuova versione)

Quindi, alla domanda vera, fa un'alternativa di ibernazione a mysqls "INSERISCI ... ON DUPLICATE "esiste la sintassi?

Oppure, se scelgo di eseguire SQL nativo per questo, posso eseguire SQL nativo all'interno di una transazione di ibernazione? Significa, supporterà commit/rollbacks?

+0

che cosa si intende per "Hibernate sta facendo un SELECT prima di ogni singolo inserto (o aggiornare) quando si utilizza saveOrUpdate()." ?potresti pubblicare il codice che stai utilizzando per salvare i dati? tra l'altro 120k records è un enorme dato! – Rakesh

+0

Ho appena trovato un articolo su [elaborazione batch in ibernazione] (http://onetouchcode.com/2016/08/21/batch-processing-example-in-hibernate/) – Shailendra

risposta

22

Ci sono molti possibili colli di bottiglia nelle operazioni di carico. L'approccio migliore dipende in larga misura dall'aspetto dei tuoi dati. Dai un'occhiata alla sezione Hibernate Manual sull'elaborazione batch.

Come minimo, assicurarsi che si sta utilizzando il seguente schema (copiato dal manuale):

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 

for (int i=0; i<100000; i++) { 
Customer customer = new Customer(.....); 
session.save(customer); 
    if (i % 20 == 0) { //20, same as the JDBC batch size 
     //flush a batch of inserts and release memory: 
     session.flush(); 
     session.clear(); 
    } 
} 

tx.commit(); 
session.close(); 

Se si sta mappando un file flat a un grafico oggetto molto complesso che si può avere per rendere più creative , ma il principio di base è che devi trovare un equilibrio tra la spinta di blocchi di dati di buona dimensione al database con ogni flush/commit ed evitare di esplodere la dimensione della cache a livello di sessione.

Infine, se non è necessario utilizzare Hibernate per gestire eventuali raccolte o collegamenti in cascata affinché i dati vengano inseriti correttamente, prendere in considerazione l'utilizzo di StatelessSession.

+0

Sto svuotando una sessione di compensazione, non ho problemi di memoria con il codice. Ho problemi con la selezione extra! : P Ho letto il manuale, non riesco a trovare nulla. I dati sono semplicissimi, non è necessario alcun collegamento a cascata. Ho solo bisogno di sbarazzarmi di, per questa operazione, selezione ridondante che viene chiamata 120K volte: P – JustDanyul

+0

@JustDanyul qual è la percentuale approssimativa di nuove entità in questa operazione (cioè quale percentuale dei selettivi non è effettivamente necessaria)? Stai usando il controllo delle versioni? – jcwayne

+0

la percentuale effettiva varia da un giorno all'altro. Tuttavia, nessuno dei selettivi dovrebbe essere davvero necessario. La maggior parte dei database oggi (anche quelli "giocattolo" come SQLite) offre funzionalità che ti consentono di aggiornare automaticamente un record se i dati esistono già. (senza dover prima eseguire il polling, per scoprire se esiste :)) – JustDanyul

0

La selezione "extra" consente di generare l'identificatore univoco per i dati.

Passare alla generazione di sequenze HiLo e ridurre il numero di roundtrip di sequenza al database per il numero della dimensione di allocazione. Si prega di notare, ci sarà un vuoto nella chiavi primarie a meno che non si regola il valore di sequenza per il generatore di HiLo

1

Se si utilizza sequenza o generatore nativo Hibernate userà una selezione per ottenere l'id:

<id name="id" column="ID"> 
    <generator class="native" /> 
</id> 

È dovrebbero usare hilo o generatore seqHiLo:

<id name="id" type="long" column="id"> 
    <generator class="seqhilo"> 
     <param name="sequence">SEQ_NAME</param> 
     <param name="max_lo">100</param> 
    </generator> 
</id> 
3

Da Hibernate Batch Processing Per l'aggiornamento ho usato il seguente:

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE") 
            .scroll(); 
int count = 0; 

while (employeeCursor.next()) { 
    Employee employee = (Employee) employeeCursor.get(0); 
    employee.updateEmployee(); 
    seession.update(employee); 
    if (++count % 50 == 0) { 
     session.flush(); 
     session.clear(); 
    } 
} 
tx.commit(); 
session.close(); 

Ma per l'inserimento vorrei andare per jcwayne risposta

Problemi correlati