Newsgroup: it.comp.java
Titolo: problemi con insert in un ciclo infinito

Salve a tutti.
Ho un problemino di performance.
In un programma ho bisogno di effettuare un bel centinaio di INSERT in una
tabella del Db (AS400 utilizzando il driver hit.as400.As400Driver)
Il problema fondamentale è che per eseguire questa insert, ci impiega ben
7 minuti. Ovviamente l'operazione la compie con un utente collegato che si
incavola e non poco per il tempo che deve aspettare.
Mi hanno consigliato di eseguire l'insert con "Blocked Insert" che a dire
il vero non so neanche che cosa vuol dire.
Qualcuno di voi per caso sa darmi qualche dritta per velocizzare i tempi
di scrittura sulla tabella??
Vi ringrazio anticipatamente.
-- 
trinity  ^_^
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 incavola e non poco per il tempo che deve aspettare.
Non conosco l'ambiente che devi usare ma, ad occhio e croce, penso che 
se tu usassi una soluzione multithread potresti ottenere notevoli 
benefici. Ad esempio potresti bufferizzare le scritture e farle eseguire 
in modo asincrono da un thread dedicato
Andrea Sini

 incavola e non poco per il tempo che deve aspettare.
quanti logici ha l'archivio? L'as (se non è un 520) ci mette un botto a fare
le insert se ci sono tante viste logiche. In questo caso usa la soluzione
multithread.

 
Ciao,
il problema con gli as400 in fase di gestione del database č la fase di 
convalida delle credenziali dell'utente e delle autorizzazioni sulle 
tabelle.
L'unico modo di migliorare le prestazioni č di aprire una sola volta la 
connessione al db as400 e cercare di fare un numero piů limitato 
possibile di accessi al database.
Se posti un pezzo di codice per capire cosa fai ora vedo se mi viene in 
mente qualcosa.

 mente qualcosa.
Allora....
// ldb è la classe LegDb che gestisce la connessione con As 400
Connection legCon = ldb.getConnection();
legCon.setAutoCommit(false);
legCon.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
// PRIMA DI TUTTO DEVO PULIRE ALCUNI ARCHIVI.....
PreparedStatement st_1 = legCon.prepareStatement( "DELETE FROM .." );
PreparedStatement st_2 = legCon.prepareStatement( "DELETE FROM .." );
PreparedStatement st_3 = legCon.prepareStatement( "DELETE FROM .."  );
st_1.executeUpdate();
st_1.close();
st_2.executeUpdate();
st_2.close();
st_3.executeUpdate();
st_3.close();
legCon.commit();  
// (non posto i blocchi try catch che gestiscono le anomalie per rendere
più leggibile possibile il codice, ma ci sono!)
// ora devo inserire, all'interno di un ciclo, tutti i valori di una
collection in una tabella.
Iterator i = collection.iterator();
while(i.hasNext()) {
String query = "INSERT INTO WDRDO00F " +
		"("            +
		"WANUM," +
		"WARIG," +
		"WASTG," +
		"WAART," +
		"WADAC," +
		"WAQTA," +
		"WAFIN"  +
		") VALUES ("   +
		rdoLine.rdoId                                  + "," +
		rdoLine.lineId                                 + "," +
		TextCvt.cvtSqlQuoted(collectionToUse)          + "," +
		TextCvt.cvtSqlQuoted(rdoLine.shortCode)        + "," +
		DateConversion.date2int(rdoLine.rqDate)        + "," +
		rdoLine.quantity                               + "," +
		TextCvt.cvtSqlQuoted (fineElaborazione)        +
		")";
PreparedStatement st = legCon.prepareStatement( query );
st.executeUpdate();
st.close();
} // fine while
legCon.commit();
// poi si esegue un altra query secca (che non posto perhcè tanto quello
che è lento è l'insert in alto. ), e alla fine nel finally c'è:
finally {
    ldb.releaseConnection(legCon);
}
 
ho lasciato nella query INSERT le formattazioni così come le uso tanto per
far capire quali operazioni sono compiute nella creazione della stringa di
query. 
TextCvt.cvtSqlQuoted inserisce semplicemente le apicette "'" agli estremi
della stringa.
DateConversion.date2int(data) trasforma la data da sql.Date in un intero
yyyyggmm.
Chissà, forse è la trasformazione della data che rallenta?
Comunque su As400 (che si trova nella sede del cliente) hanno letto il log
(credo) e hanno detto che il file che viene scritto (forse dalla gestione
di as400) scrive 3 record al secondo: MOLTO LENTAMENTE. Come se o il
driver, oppure il mio programma (questo postato) facesse arrivare ad As
400 la composizione della query molto lentamente. 
La stessa query se lanciata direttamente su As viene eseguita in
nanosecondi.
Se ti servono altre informazioni, dimmelo.
Grazie ancora.


Che versione di sistema operativo hanno e che tipo di macchina??
Ti spiego il perchè:
Interagire dall'esterno su una macchina diversa dai modelli 5xx e/o con 
sistemi operativi precedenti alla 5.1.x è una cosa terribile.
Il codice che hai postato mi sembra efficiente, ma mi viene in mente una 
idea per velocizzare il tutto.
Crei un file di testo a lunghezza fissa, con i dati che devi scrivere su 
as400, e lo trasferisci via FTP su un file di appoggio su AS400.
Dopodichè lanci un SQL del tipo:
INSERT INTO
   WDRDO00F
   (WANUM,
    WARIG,
    ....,
    WAFIN
   )
SELECT
   APNUM,
   APRIG,
   ....,
   APFIN
FROM
   <file fisico di appoggio>
e alla fine di tutto pulisci il file di appoggio.
In questo modo ottieni che il trasferimento via FTP è molto veloce ed 
esegui una singola istruzione SQL al posto di 1 per ogni record.
In alternativa potresti creare una Stored Procedure su AS400 (non è 
altro che un programma in COBOL o RPG IV) che esegue la scrittura dal 
file di appoggio.
Fammi sapere cosa ne pensi.
^_^ trinity ha scritto:


Il codice che hai postato non è efficiente !
Se ho capito bene ad ogni iterazione prepari un nuovo statement e lo
esegui...
Dovresti creare uno statement parametrico tipo INSERT INTO .... VALUES
(?,?,?,...)prepararlo una volta sola al di fuori del ciclo e
all'interno impostare i parametri ed eseguire  solo l'insert. Questo
migliora sicuramente le performance.
Non mi è chiaro se il tuo programma java gira sull'AS400 oppure ti
colleghi all'AS in remoto da un PC.
Nel primo caso dovresti usare il driver nativo di DB2 dell'AS400 che ti
garantisce performance di gran lunga migliori.
Se invece ti colleghi da un PC perchè non usi il driver del Toolbox di
AS400 ?
Cmq 3 record al secondo sono un tempo spaventoso!!!

 yyyyggmm.
Puoi usare la classe DateFormat per questo:
http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html
Buon lavoro !
-- 
Giambo - Occhio al filtro antispam _e_ alla whitelist !

Prova a dare un'occhiata qui
http://java.sun.com/docs/books/tutorial/jdbc/jdbc2dot0/batchupdates.html

Innanzi tutto grazie a tutti per le risposte, mi sono state utilissime.
Rispondo qui per tutti alle varie cose che mi avete chiesto:
Per
 - B. Daniele. Non posso utilizzare l'FTP perhcè non c'è. Lo avevamo
chiesto per altre operazioni (vedi deploy) ma hanno risposto picche. Il
server è loro e si trova in un altra città. Il sistema operativo è Windows
2000 Terminal
 - pioneer e Giambo - 
 proverò entrambe le soluzioni. Molto efficiente mi sembra quella del
BatchUpdate. Speriamo di risolvere. Comunque mi collego ad As400 tramite
accesso remoto e i tool da utilizzare sono un pò "forzati".
Grazie a TUTTI. Mi siete stati di grande aiuto.
Inizio subito con le prove e vi farò sapere.
Ciao



Prego (per batchUpdate).
Per quanto riguarda quello che scrivi qui, è ovvio perchè:
1) esegui la query in locale dove la connessione al DB è sempre aperta
(non conosco AS400, conosco l'Host (OS390) e presumo che tu l'abbia
provata con qualcosa tipo QMF o Spufi).
2) Non c'è passaggio di informazioni via rete.
3) Effettivamente tu instanziavi un nuovo oggetto per ogni insert
invece di usare sempre lo stesso.

FUNZIONA PERFETTAMENTE.
CI METTE QUALCHE SECONDO AD ESEGUIRE PIU' DI 1400 RECORD.
Ho un solo problema.
Il programma deve fare questo:
Scrivere su un archivio, e rileggere le risposte.
Quindi dopo la fatidica INSERT, vado a fare la SELECT, per recuperare il
risultato.
Finchè da questa select non esce un valore > 0 continuo a farla.
Il fatto è che mi si è velocizzata la insert, ma ora mi va in timeout la
select. Però appena mi ritorna l'errore, la select ritorna il valore
corretto. E' come se in realtà l'insert non venisse percepita dall'AS 400
Vi posto un pò di codice, magari mi manca qualche istruzione tipo commit.
Statement stmt = legCon.createStatement();
while( ... ){
String query = String query = "INSERT INTO WDRDO00F " +
"(" +
"WANUM," +
"WARIG," +
"WASTG," +
"WAART," +
"WADAC," +
"WAQTA," +
"WAFIN" +
") VALUES (" +
rdoLine.rdoId + "," +
rdoLine.lineId + "," +
TextCvt.cvtSqlQuoted(collectionToUse) + "," +
TextCvt.cvtSqlQuoted(rdoLine.shortCode) + "," +
DateConversion.date2int(rdoLine.rqDate) + "," +
rdoLine.quantity + "," +
TextCvt.cvtSqlQuoted (fineElaborazione) +
")";
stmt.addBatch(query);
}
int [] updateCounts = stmt.executeBatch();
stmt.close();
legCon.commit();
...
// rilascio la connessione
finally {
ldb.releaseConnection(legCon);
}
// poi la riapro per la lettura del risultato.
ed eseguo una select classica..
String s6 = 
"SELECT WGSTA FROM WPSRO00F " +
"WHERE " +
"(WGNUM = " + nrRdo + ") AND " +
"(WGDIR = 'RES') AND " +
"((WGSTA = 1) OR (WGSTA = 2))";
Statement st6 = legCon.createStatement();
ResultSet rs6 = st6.executeQuery( s6 );
-.....
ecc. ecc.
ora questa seconda select non ritorna mai il WGSTA = 1, che vuol dire che
ha lavorato il mio inserimetno. La cosa STANA è che appena mi va in
timeout la select ritorna il corretto valore. Come se sbloccassi qualcosa
e a quel punto riesce ad elaborare la mia insert.
Per caso mi manca qualcosa nel comando executeBatch();????
Grazie.
Ale


Ciao,
molto semplicemente dopo l'insert tu hai un lock sul record inserito e 
per sbloccarlo devi fare una commit work.
La sequenza deve essere Insert, Commit, Select.
Ciao.
^_^ trinity ha scritto:


 Ciao.
MA io gia faccio la commit.
Comunque non so da cosa dipenda, ma la select me l'ha bloccata per un paio
di prove dopo diche ora funziona tutto regolarmente.
Grazie a tutti voi


Se i driver che usi le supportano, prova con batch update
(
http://java.sun.com/docs/books/tutorial/jdbc/jdbc2dot0/batchupdates.html
)


(
http://java.sun.com/docs/books/tutorial/jdbc/jdbc2dot0/batchupdates.html
)
Eh...non sei stato attento....:)

Vero :) Ho letto solo dopo che s'era gia' oltre