|
|
|
![]() |
|
Strumenti |
![]() |
#21 | |
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
@sottovento: se i file da cui estrarre le informazioni sono in formato csv, Python ha un modulo già integrato ad hoc. Al solito, basta dare un'occhiata veloce agli esempi per capire come usarlo (il reader è semplicissimo).
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
![]() |
![]() |
![]() |
#22 |
Bannato
Iscritto dal: Mar 2008
Città: Villabate(PA)
Messaggi: 2515
|
![]() ![]() |
![]() |
![]() |
![]() |
#23 | |
Senior Member
Iscritto dal: Oct 2001
Messaggi: 11471
|
Quote:
Se il problema è veramente l'i/o e il db non è enorme si potrebbe provare ad usare un ramdisk. Su una macchina linux basta creare il file in /dev/shm. |
|
![]() |
![]() |
![]() |
#24 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
Prima impressione: wow! Va come una sgiavella! Quando prima mi servivano una ventina di minuti per fare il lavoro che mi serviva, ora servono una trentina di secondi, tempo piu' che accettabile per quel che devo fare. Piccolo problema: ho dei record con una marea di campi, e la stringa di insert fallisce quando e' troppo lunga. Devo studiare una soluzione (probabilmente dovro' spezzare la query in una serie di insert + update).
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#25 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
Beh, nel caso in questione il problema era palesemente il driver. Cmq il suggerimento e' buono, anche se non applicabile nel mio caso. Grazie comunque!
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#26 | |
Bannato
Iscritto dal: Mar 2008
Città: Villabate(PA)
Messaggi: 2515
|
Quote:
![]() ![]() ![]() ![]() |
|
![]() |
![]() |
![]() |
#27 |
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2776
|
Alla fine il tempo l'ho misurato con time.clock() e time.perf_counter(), ci mette dai 16 ai 19 secondi.
Il db finale è grande circa 110 MB. In python 2.7: Codice:
import sqlite3 import time start = time.clock() conn = sqlite3.connect('example.db') c = conn.cursor() NumStrings = 100 NumIntegers = 100 # Create table c.execute('create table two_hundred_one (id integer, %s)' % ', '.join(['str_%s text' % i for i in xrange(1, NumStrings + 1)] + ['int_%s integer' % i for i in xrange(1, NumIntegers + 1)])) t = tuple(['Text_%s' % i for i in xrange(1, NumStrings + 1)] + range(1, NumIntegers + 1)) Query = 'insert into two_hundred_one values (%s' + ', ?' * (NumStrings + NumIntegers) + ')' for id in xrange(1, 100001): c.execute(Query % id, t) # Save (commit) the changes conn.commit() # We can also close the cursor if we are done with it c.close() end = time.clock() print('Total time: ' + str(end - start)) Codice:
import sqlite3 import time NUM_TEXT = 100 NUM_INTEGER = 100 start = time.perf_counter() conn = sqlite3.connect('example.db') c = conn.cursor() # Create table c.execute('create table two_hundred_one (id integer, %s)' % ', '.join(['str_%s text' % i for i in range(1, NUM_TEXT + 1)] + ['int_%s integer' % i for i in range(1, NUM_INTEGER + 1)])) t = tuple(['Text_%s' % i for i in range(1, NUM_TEXT + 1)] + list(range(1, NUM_INTEGER + 1))) insert = 'insert into two_hundred_one values (%s' + ', ?' * (NUM_TEXT + NUM_INTEGER) + ')' for id in range(1, 100001): c.execute(insert % id, t) # Save (commit) the changes conn.commit() # We can also close the cursor if we are done with it c.close() end = time.perf_counter() print('Total time: ' + str(end - start)) |
![]() |
![]() |
![]() |
#28 | ||||
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
Ho un progetto che usa MySQL, e una batteria con circa 400 test, che impiega circa 4 minuti per essere eseguita ogni volta. Purtroppo non esiste modo di spostare programmaticamente il data store da un'altra parte. Con SQLite o Firebird posso decidere di aprire file ovunque, mentre con MySQL dovrei: fermare il server, copiare tutti i file dalla datadir alla ram disk, e farlo ripartire. Fattibile se hai una datadir piccola, ma se contiene diversi database e supera il GB, diventa troppo pesante. ![]() Quote:
Quote:
Quote:
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
||||
![]() |
![]() |
![]() |
#29 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
![]()
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#30 |
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Allora è molto probabile che sia quello il problema. Anche se mi sembra veramente strano: è un limite incomprensibile.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
![]() |
![]() |
![]() |
#31 |
Senior Member
Iscritto dal: May 2007
Città: Milano
Messaggi: 7103
|
Ellapepa quanti attributi...
Inviato dal mio Sony Xperia P
__________________
Apple Watch Ultra + iPhone 15 Pro Max + Rog Ally + Legion Go |
![]() |
![]() |
![]() |
#32 | |
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Trovato il problema. Da qui:
Quote:
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
![]() |
![]() |
![]() |
#33 |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Bene! Beh, mi sembra che siano stati risolti tutti i problemi, no?
Le prestazioni scadenti erano dovuti al driver (o meglio, alla sua implementazione), e sappiamo anche perche' le mie query fallivano. Grazie a tutti!!
__________________
In God we trust; all others bring data |
![]() |
![]() |
![]() |
#34 |
Bannato
Iscritto dal: Mar 2008
Città: Villabate(PA)
Messaggi: 2515
|
Aspetta aspetta!
Perché non ci spieghi un attimino come funziona sqlite4java visto che la documentazione su GoogleCode è carente? Una sorta di mini corso, un "getting started" migliore di quello che si trova nel sito ufficiale. ![]() |
![]() |
![]() |
![]() |
#35 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
Io ho proceduto per tentativi, facendo delle supposizioni e non toccando piu' nulla quando ho ottenuto quello che mi serve. Ovviamente il lavoro andrebbe approfondito, ma preferisco fare altro, nella mia vita ![]() Collegamento: l'esempio che hai riportato funziona bene: Codice:
db = new SQLiteConnection(new File(sqliteFile)); db.open(true); Nel tuo esempio, c'era una query ma non una insertion. Ecco qui. Per prima cosa ho cancellato la tabella, cosi' da ricrearla (i miei campi possono cambiare a seconda del macchinario da cui ho prelevato i dati): Codice:
try { db.exec("BEGIN"); query = "DROP TABLE " + tableName; SQLiteStatement stmtDrop = db.prepare(query); stmtDrop.step(); db.exec("COMMIT"); stmtDrop.dispose(); } catch (Exception ee) { //System.out.println (ee.toString()); db.exec("ROLLBACK"); } Da notare: - aprire la transazione con db.exec("BEGIN"); -creare lo statement ed eseguirlo; - chiudere la transazione con db.exec("COMMIT"); - chiudere la transazione con db.exec("ROLLBACK") in caso di errore; - dispose dello statement. Esiste anche l'autocommit ed immagino esistano anche altre opzioni che probabilmente evitano questi passaggi. Non le ho provate ne' cercate. Per creare la tabella, ho provato un altro stile, ma non so dire quale sia meglio: Codice:
db.exec("BEGIN"); String query = buildCreateTableQuery(tableName, model); db.exec(query); db.exec("COMMIT"); Anche qui occorre prestare attenzione a fare il ROLLBACK nel caso l'operazione fallisca; altrimenti tutte le altre operazioni continueranno a fallire. Per l'inserimento dei dati ho usato una preparedStatement: Codice:
String query = buildInsertQuery(tableName, model); SQLiteStatement st = db.prepare(query); In accordo con il mio software, ho poi effettuato il binding per ogni record letto da file, ed eseguito l'operazione: Codice:
for (int i = 0; i < l; i++) { String strType = model.getValueAt(i, 3).toString(); switch (strType) { case "INT": st.bind(i+1, Integer.parseInt(vect[i])); break; case "DOUBLE": st.bind(i+1, Double.parseDouble(vect[i])); break; default: st.bind(i+1, vect[i]); break; } } st.step(); countSuccess++; st.reset(true); Non conoscendo nulla riguardo l'area di commit (grandezza, prestazioni,....) ho deciso di fare BEGIN...COMMIT/ROLLBACK ogni 100 record. Non ho voluto indagare di piu' per mancanza di tempo. Da notare st.reset() che effettua l'unbinding in modo che al ciclo successivo possa fare il binding con i nuovi valori. Penso che questo reset possa essere evitato in casi si usi un reference (in tal caso immagino basti aggiornare l'oggetto referenziato), ma e' solo un'ipotesi
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#36 |
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2776
|
Ho riscritto lo stesso test anche in java e penso di aver trovato l'inghippo.
Posto le due versioni, quella lenta e quella veloce: Lenta: Codice:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.sql.PreparedStatement; public class TestSqlite { public static int NUM_TEXT = 100; public static int NUM_INTEGER = 100; public static int NUM_INSERT = 10000; public static void main(String[] args) throws ClassNotFoundException { long start = System.nanoTime(); // load the sqlite-JDBC driver using the current class loader Class.forName("org.sqlite.JDBC"); Connection connection = null; try { // create a database connection connection = DriverManager.getConnection("jdbc:sqlite:sample.db"); Statement statement = connection.createStatement(); statement.setQueryTimeout(30); // set timeout to 30 sec. statement.executeUpdate("drop table if exists two_hundred_one"); String create = "create table two_hundred_one (id integer"; for(int i=1; i<=NUM_TEXT; i++){ create += ", text_" + i + " text"; } for(int i=1; i<=NUM_INTEGER; i++){ create += ", int_" + i + " integer"; } create += ")"; statement.executeUpdate(create); String insert = "insert into two_hundred_one values(?"; for(int i=0; i<NUM_TEXT + NUM_INTEGER; i++){ insert += ", ?"; } insert += ")"; PreparedStatement preparedStatement = connection.prepareStatement(insert); for(int i=1; i<=NUM_TEXT; i++){ preparedStatement.setString(i + 1, "Text_" + i); } for(int i=1; i<=NUM_INTEGER; i++){ preparedStatement.setInt(NUM_TEXT + i + 1, i); } for(int i=1; i<=NUM_INSERT; i++){ preparedStatement.setInt(1, i); preparedStatement.executeUpdate(); } } catch(SQLException e) { // if the error message is "out of memory", // it probably means no database file is found System.err.println(e.getMessage()); } finally { try { if(connection != null) connection.close(); } catch(SQLException e) { // connection close failed. System.err.println(e); } } long end = System.nanoTime(); System.out.println("Total time: " + (float)(end-start)/1000000000 ); } } ![]() Ed ecco invece la versione veloce: Codice:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.sql.PreparedStatement; public class TestSqlite { public static int NUM_TEXT = 100; public static int NUM_INTEGER = 100; public static int NUM_INSERT = 100000; public static void main(String[] args) throws ClassNotFoundException { long start = System.nanoTime(); // load the sqlite-JDBC driver using the current class loader Class.forName("org.sqlite.JDBC"); Connection connection = null; try { // create a database connection connection = DriverManager.getConnection("jdbc:sqlite:sample.db"); connection.setAutoCommit(false); Statement statement = connection.createStatement(); statement.setQueryTimeout(30); // set timeout to 30 sec. statement.executeUpdate("drop table if exists two_hundred_one"); String create = "create table two_hundred_one (id integer"; for(int i=1; i<=NUM_TEXT; i++){ create += ", text_" + i + " text"; } for(int i=1; i<=NUM_INTEGER; i++){ create += ", int_" + i + " integer"; } create += ")"; statement.executeUpdate(create); String insert = "insert into two_hundred_one values(?"; for(int i=0; i<NUM_TEXT + NUM_INTEGER; i++){ insert += ", ?"; } insert += ")"; PreparedStatement preparedStatement = connection.prepareStatement(insert); for(int i=1; i<=NUM_TEXT; i++){ preparedStatement.setString(i + 1, "Text_" + i); } for(int i=1; i<=NUM_INTEGER; i++){ preparedStatement.setInt(NUM_TEXT + i + 1, i); } for(int i=1; i<=NUM_INSERT; i++){ preparedStatement.setInt(1, i); preparedStatement.executeUpdate(); } connection.commit(); } catch(SQLException e) { // if the error message is "out of memory", // it probably means no database file is found System.err.println(e.getMessage()); } finally { try { if(connection != null) connection.close(); } catch(SQLException e) { // connection close failed. System.err.println(e); } } long end = System.nanoTime(); System.out.println("Total time: " + (float)(end-start)/1000000000 ); } } Cosa cambia nella seconda versione? Che ho usato una transazione. In sostanza la versione lenta scriveva su disco a ogni insert o quasi, infatti da esplora risorse vedevo il file del db crescere pian pianino. |
![]() |
![]() |
![]() |
#37 |
Bannato
Iscritto dal: Mar 2008
Città: Villabate(PA)
Messaggi: 2515
|
Perfetto, Sottovento, grazie mille
![]() P.S.: l'esempio che ho postato l'ho copincollato dalla pagina "getting started" del sito ufficiale. Mi sembrava un po' pochino così ti ho chiesto questa miniguida. A complemento della documentazione ufficiale. ![]() Ultima modifica di Vincenzo1968 : 03-03-2013 alle 17:59. |
![]() |
![]() |
![]() |
#38 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
A questo punto, appena ho tempo, cerchero' di fare il confronto fra versione con autocommit = false e quella scritta con le primitive suggerite da Vincenzo, per capire quanto overhead si porta via il driver... penso sia interessante per capire quali margini ci sono, i.e. se vale la pena esser standard o esser veloci ![]()
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#39 | |
Senior Member
Iscritto dal: Oct 2001
Messaggi: 11471
|
Quote:
In questo modo però se step() o la commit lanciano una eccezione la dispose() non è mai invocata. Dovresti metterla in una finally {}. Trattandosi di una libreria jni meglio non rischiare. |
|
![]() |
![]() |
![]() |
#40 | |||
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
Quote:
Al più, visto che ho 4 core, potrei pensare di parallelizzarli, ma sarebbe un lavoraccio pure quello (dovrei creare 4 alias per il database, e lanciare 4 processi, uno per ogni core, che si smazzano ognuno 1/4 dei test), però l'hd è soltanto uno, ed è pure meccanico (niente SSD finora), per cui non so quanto si potrebbe guadagnare alla fine. Credo che mi convenga sbattere la testa cercando qualche soluzione per usare una ram disk. Stavo pensando di creare una datadir soltanto per questo progetto, che quindi occuperà poco spazio. Tutti gli altri database staranno nel datadir che occupa molto più spazio. Creando qualche script per impostare il datadir desiderato, dovrei riuscire a cavarmela in qualche modo. Quote:
![]()
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|||
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 11:01.