Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 14

Discussione: Lentezza Java -> MySQL

  1. #1

    Lentezza Java -> MySQL

    Ciao a tutti. Ho realizzato un software che effettua una sorta di catalogazione dei file scelti. Praticamente salva all'interno di un DB, in MySQL, la lista delle varie informazioni dei file scelti. Attenzione...non vengono salvati i file, ma solo le informazioni quali nome, dimensione, ecc...
    Ho lanciato una catalogazione di 34680 file e ci ha messo a scriverli sul DB ben 14 minuti.
    Premetto che il software è in Java e il DB è in MySQL e utilizzo l'ultimo driver mysql-connector-java-5.1.17. Vi posto inoltre i metodi principali per eseguire la query:

    Per connettermi in una classe ho inserito questo metodo:

    codice:
    private Boolean Connessione(){ 
            XML xml = new XML();
            xml.getXML();
            connesso=false;
            try{
                Class.forName("com.mysql.jdbc.Driver");
                
                connessioneDB = DriverManager.getConnection("jdbc:mysql://"
                        + xml.parametriConnessioneDB[0] + ":" 
                        + xml.parametriConnessioneDB[1] + "/" 
                        + xml.parametriConnessioneDB[2]                      
                        + "?user=" + xml.parametriConnessioneDB[3]
                        + "&password=" + xml.parametriConnessioneDB[4]);
                
                connesso=true;
                
            }catch(Exception exc){            
                frmConfiguraConnessione frame = new frmConfiguraConnessione();
                frame.setVisible(true);            
            }
            return connesso;
        }
    Fin qui tutto apposto e per lavorare sul DB invio questa query:

    codice:
    for(int i = 0; i <arraySize; i++){
                                
         convertiNomeFilePerSQL = listaFile[i].getName();
         convertiPathPerSQL = listaFile[i].getParent();
         db.EseguiSQL("INSERT INTO precatalogati "
                + "(nomefile, tipofile, "
                + "dimensionefile, tiposupporto, nomesupporto, "
                + "datacatalogazione, path) VALUES "
                + "('" + convertiNomeFilePerSQL.replaceAll("'", "''") + "', "
                + "'" + getExtension(listaFile[i]) + "', " 
                + "" + listaFile[i].length() + ", "
                + "'" + cmbTipoSupporto.getSelectedItem() + "', "
                + "'" + txtNomeSupporto.getText() + "', "
                + "'" + txtDataCatalogazione.getText() + "', "
                + "'" + convertiPathPerSQL.replaceAll("'", "''") + "');"); 
    }
    Che viene data in pasto al metodo presente sempre dentro la classe dove effettuo la connessione al DB:

    codice:
    public void EseguiSQL(String sql){        
            try{            
                PreparedStatement ps = connessioneDB.prepareStatement(sql);                        
                ps.executeUpdate();
                ps.close(); 
                
            }catch(SQLException exc){
                JOptionPane.showMessageDialog(null, exc.getMessage().toString(),
                "Errore!", JOptionPane.ERROR_MESSAGE);
            }        
        }
    Premetto che il programma funziona alla perfezione, ma purtroppo ha questo enorme inconveniente relativo alla velocità di esecuzione delle query. Potreste aiutarmi? Grazie.

  2. #2
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Hai almeno due fattori che ti generano questa "lentezza".

    Punto primo hai una serie di concatenazioni di stringhe dentro ad un ciclo: questo è pessimo. Usa uno StringBuffer o uno StringBuilder e la velocità aumenta di molto.

    In secondo luogo stai costruendo per niente una serie di PreparedStatement. Generalmente PreparedStatement si usa per poter riutilizzare una query più volte con parametri diversi: tu ne stai creando una per ogni inserimento (il contrario di come andrebbero usate) e, per di più, non ne fai un uso parametrico, ma le usi come normali Statement.

    Ti consiglio di approfondire l'argomento per poter migliorare il tuo codice e renderlo decisamente più efficiente.

    Per quanto riguarda StringBuilder / StringBuffer se n'è parlato proprio ieri in questa discussione

    http://forum.html.it/forum/showthrea...readid=1483179

    ma in questo caso, con un uso sapiente delle PreparedStatement, direi che puoi tranquillamente buttare tutte quelle concatenazioni e usare un metodo che riceve, invece, diversi parametri.


    Per quanto riguarda PreparedStatement, leggi bene la documentazione che riporta un esempio d'uso proprio nell'intestazione e cerca di far sì che venga riutilizzata la stessa PreparedStatement, a cui verranno passati, di volta in volta, i parametri variabili.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  3. #3
    Ciao LeleFt e grazie, sei stato molto chiaro. Ora farò le varie modifiche e prove del caso e posto il risultato così che possa essere di aiuto a qualcun altro.


    Stavo effettuando le varie modifiche, ma non capisco come possa modificare questo metodo:

    codice:
    public void EseguiSQL(String sql){        
            try{            
                PreparedStatement ps = connessioneDB.prepareStatement(sql);                        
                ps.executeUpdate();
                ps.close(); 
                
            }catch(SQLException exc){
                JOptionPane.showMessageDialog(null, exc.getMessage().toString(),
                "Errore!", JOptionPane.ERROR_MESSAGE);
            }        
        }
    io comunque per inserire i dati in tabella devo usare un ciclo perché devo prelevare i dati salvati dentro un'array di file da parte di una JFileChooser e poi passarli al DB...

  4. #4
    Ci sono riuscito...ora è un missile.

    A breve la soluzione. Grazie.

  5. #5
    Ho fatto così, chiaramente mi devi dire se per te è una scelta appropriata:

    codice:
    public void creaStatement(String sql){
            
            try{
                
                ps = connessioneDB.prepareStatement(sql);
                
            }catch(SQLException exc){
                
                JOptionPane.showMessageDialog(null, exc.getMessage(),
                "Errore metodo creaStatement!", JOptionPane.ERROR_MESSAGE);
            }
        }
    
        public void popolaStatement(String nomefile, String tipofile, 
                Long dimensionefile, String tiposupporto, String nomesupporto, 
                String datacatalogazione, String path){
            
            try{
                ps.setString(1, nomefile);
                ps.setString(2, tipofile);
                ps.setLong(3, dimensionefile);
                ps.setString(4, tiposupporto);
                ps.setString(5, nomesupporto);
                ps.setString(6, datacatalogazione);
                ps.setString(7, path);
                ps.executeUpdate();
            }catch(SQLException exc){
                
               JOptionPane.showMessageDialog(null, exc.getMessage(),
                "Errore metodo popolaStatement!", JOptionPane.ERROR_MESSAGE);
            }
        }
    
        public void lanciaStatement(){
            try{
                ps.executeUpdate();
            }catch(SQLException exc){
                JOptionPane.showMessageDialog(null, exc.getMessage(),
                "Errore metodo lanciaStatement!", JOptionPane.ERROR_MESSAGE);
            }
        }
    Poi nel form dove catalogo i file prelevati eseguo il tutto in questa maniera:

    codice:
    db.creaStatement("INSERT INTO precatalogati "
                        + "(nomefile, tipofile, "
                        + "dimensionefile, tiposupporto, nomesupporto, "
                        + "datacatalogazione, path) VALUES "
                        + "(?, ?, ?, ?, ?, ?, ?);");
                            
    for(int i = 0; i <arraySize; i++){
                        
                                db.popolaStatement(convertiNomeFilePerSQL.replaceAll("'", "''"), 
                                getExtension(entries[i]), entries[i].length(), 
                                cmbTipoSupporto.getSelectedItem().toString(), 
                                txtNomeSupporto.getText(), 
                                txtDataCatalogazione.getText(), 
                                convertiPathPerSQL.replaceAll("'", "''"));
     }     
    db.lanciaStatement();
    Cosa ne pensi? Fammi sapere.

  6. #6
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    C'è una cosa che non mi torna: con quel codice esegui due volte l'inserimento dell'ultima riga, la prima quando popoli la PreparedStatement (dopo aver settato tutti i campi esegui un executeUpdate() ) e una seconda volta quando poi richiami "lanciaStatement()" al di fuori del ciclo for.

    Per i problemi di lentezza, direi che non ho elementi sufficienti per capire dove possa esserci il collo di bottiglia. Tu richiami diversi metodi per passare i parametri alla Statement...

    Al momento non ho modo di effettuare un test simile. Se domani mi avanza del tempo proverò a costruirmi un ambiente di test simile al tuo.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  7. #7
    Il doppio executeUpdate è stato un errore mio di distrazione, infatti non serve a nulla. L'antifona però non cambia e resta lento...non capisco proprio. Comunque attendo tue notizie e grazie ancora. A presto.

  8. #8
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Sto facendo proprio ora il test. Per 35.000 record ha impiegato 18 minuti. Sono poco meno di 2.000 record al minuto.

    Ho eseguito il test su una macchina Win XP SP3, con 3 GB di RAM, MySQL 5.0.27 in locale.

    La tabella su cui ho fatto il test:

    nomefile VARCHAR(80)
    tipofile VARCHAR(10)
    dimensionefile DOUBLE
    tiposupporto VARCHAR(20)
    nomesupporto VARCHAR(200)
    datacatalogazione VARCHAR(10)
    path VARCHAR(200)

    Il codice usato per il test:

    codice:
    db.createStatement("INSERT INTO tabella VALUES(?,?,?,?,?,?,?)");
    
    for(int i=0; i<35000; i++) {
       db.popolaStatement("nome_file_" + i, "XML", getRandomLong(), "Floppy", "Nome del supporto " + i, "2011-11-08", getNewPath(i));
       db.eseguiAggiornamento();
    
       // Ogni 1000 inserimenti stampa un asterisco (per vedere l'avanzamento)
       if ((i % 1000) == 0) {
          System.out.print("* ");
       }
    }
    
    ...
    private static Long getRandomLong() {
       Long l = rand.nextLong();   // rand è un oggetto Random
       return (l > 0L) ? l : -1 * l;
    }
    
    private static String getNewPath(int i) {
       // nForm è un NumberFormat che formatta i numeri su 5 cifre, con 0 come padding
       return "/home/mio/path/" + nForm.format(i) + "/";
    }
    Sinceramente non saprei dire se è "lento" o "veloce". 2000 record al minuto sono 33 record al secondo. Considerando che la tabella è quasi esclusivamente composta di stringhe...

    C'è anche da dire che almeno 3 minuti sono stati spesi dal DBMS per chiudere la connessione (quindi, probabilmente, li ha usati per scaricare la cache delle scritture).

    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  9. #9
    Lo ritengo un tempo non accettabile per un motivo. Se faccio il programma in Access è una scheggia. Inoltre mio cugino, che sviluppa molto in PHP, ha fatto la stessa cosa, da PHP, e a lui 100000 righe le fa tipo in 10 minuti (10000 righe al minuto). Mi sa proprio che MySQL e Java non vanno molto d'accordo. Sai che ti dico? Che provo a cambiare DB e uso le tabelle di Access e ti faccio sapere. Intanto ti ringrazio per aver provato il mio codice.

    P.S.
    Premetto che io l'ho provato su una macchina Win 7 Ultimate 64Bit, con MySQL 5.2 in locale, 4GB di RAM e CPU Intel Quad Core da 3Ghz.

  10. #10
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Ho effettuato un nuovo test usando JPA.
    Ha impiegato meno di 40 secondi.

    Effettivamente quell'approccio non va. JPA riesce ad effettuare delle ottimizzazioni maggiori.

    Questo il codice:

    codice:
            EntityManagerFactory emf = Persistence.createEntityManagerFactory("InsertDBMultiploPU");
            EntityManager em = emf.createEntityManager();
    
            if (em != null) {
                em.getTransaction().begin();
    
                for(int i=0; i<35000; i++) {
                    Tabella t = new Tabella();
                    t.setNomefile("nome_file_" + i);
                    t.setTipofile("XML");
                    t.setDimfile( getRandomLong() );
                    t.setTiposupporto("Floppy");
                    t.setNomesupporto("Nome del supporto " + i);
                    t.setDatacatalogo("2011-11-08");
                    t.setPath( getNewPath(i) );
    
                    em.persist(t);
                    if ((i % 1000) == 0) {
                        System.out.print("* ");
                    }
                }
    
                em.getTransaction().commit();
    
                em.close();
            }
    
            emf.close();
    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.