java optimieren. wie daten schneller in mysqlDB schreiben?

Status
Nicht offen für weitere Antworten.

gondor

Bekanntes Mitglied
hallo java-freunde!

ich habe ein problem beim einlesen großer textdateien.

und zwar werden einzelne werte in eine db (mySQL) geschrieben:

das textfile hat folgende struktur:

[..]
2004-12-12 13:01:12 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000
2004-12-12 13:01:13 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000
2004-12-12 13:01:14 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000
2004-12-12 13:01:15 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000
2004-12-12 13:01:16 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000
2004-12-12 13:01:17 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000
[..]

das einlesen mit meinem java-programm dauert alleine schon bei ca. 100 zeilen á 8 spalten um die
20 sekunden. da eine datei rund 500.000 zeilen beinhalten kann, würde das stunden brauchen, was
deutlich zu lange ist. der ablauf ist folgend: eine zeile wird eingelesen und jeder einzelne wert
in mysql eingeschrieben bzw. die querie dafür in einen vector gespeichert. das zusammenstellen und
einlesen geschieht hier:

diese methode wird von einem thread gestartet, der mir die werte in die db schreibt:

Code:
private boolean parseData_DateTime(C_ImportFile import_file_, int recordID_) {

        System.out.println("C_Import --> parseData_DateTime");

        String datetime = "0000-00-00 00:00:00";

        /*Error-Flag*/
        boolean error_parse = true;

        int progress_counter = 0;

        /*Sensoren*/
        List sensors = null;

        /*Sensor-Zeile*/
        String buffer = null;

        /*File wird gepuffert eingelesen*/
        BufferedReader br = null;

        Vector query_update = new Vector();

        try {

            br = new BufferedReader(new FileReader(import_file_.getAbsolutePath()));

            /*Sensoren*/
            sensors = new Vector();

            while ((buffer = br.readLine()) != null && !this.interrupted) {

                this.setValue(progress_counter++);

                if (buffer.matches("Zeit \\[.*?")) {

                    /*Header mit Sensoren einlesen*/
                    sensors = this.parseHeader(buffer);

                } else if (!sensors.isEmpty()) {

                    String[] tokens = buffer.split(this.seperator_property);

                    for (int i = 0; i < tokens.length; i++) {

                        SensorHeader header = ((SensorHeader) sensors.get(i));

                        int sensorID = measurement_sensor.getSensorID(header.getName(), header.getType().getId());

                        if (header.getType().getId() == C_HeaderConstant.UNIT_TIME_ID) {
                            datetime = tokens[i];
                        } else {
                            String command = "INSERT INTO " + C_SensorValueTable.TableName + " (" + C_SensorValueTable.SensorValueSensorID + ", " + 
C_SensorValueTable.SensorValueRecordID + ", " + C_SensorValueTable.SensorValueMeasurementTime + ", " + C_SensorValueTable.SensorValue + ") VALUES (" + sensorID + ", " 
+ recordID_ + ", '" + datetime + "', " + Double.parseDouble(tokens[i]) + ");";
                            query_update.add(command);
                        }
                    }
                }
            }

            query_sensor_value.queryUpdate(query_update);

        } catch (Exception ex) {
            /*** Errorhandling ***********************************/
            System.out.println("Error: parseData_DateTime (Exception)");
            cat.error("Error: parseData_DateTime (Exception)");

            error_parse = false;
        }

        return error_parse;
    }

die einzelnen queries werden von mir in einen vector gespeichert und an query_update geschickt:

Code:
public void queryUpdate(Vector queries_) {

        Vector queries = queries_;

        Statement st = null;

        this.openConnection();

        String command = null;

        try {

            Iterator it = queries.iterator();

            while (it.hasNext()) {

                st = this.mySQL_connection.createStatement();
                st.addBatch(it.next().toString());
                st.executeBatch();
            }

        } catch (SQLException ex) {
            /*** Errorhandling ***********************************/
            System.out.println("Error: queryUpdate (SQLException)");
            cat.error("Error: queryUpdate (SQLException)");
        }

        this.closeConnection();

}

auch die verwendung von prepare statements brachte keinen wirklichen fortschritt.

wie kann ich meinen java-code optimieren, damit meine daten wesentlich 'schneller'
in die db geschrieben werden können. laut mySQL gibt es den befehl LOAD DATA INFILE,
der ein ganzes File innerhalb von sekunden in eine tabelle einlesen kann. könnte ich
damit evtl. weiterkommen?

wäre hier sehr auf hilfe angewiesen und würde mich freuen, wenn mir ein guter tipp
zum weiterentwickeln gegeben wird.

herzlichen dank,

gondor(..)

edited by thE_29: auch hier abgeteilt
 
Vermutlich bricht dir das '+' das Genick!
Wo immer es geht nicht mit String, sondern mit StringBuffer arbeiten, besonders bei diesen Datenmengen.
Am besten man gewöhnt sich String + String komplett ab und vergisst das dieser Operator jemals überladen wurde :wink:
 
@wildcard

danke für deine schnelle hilfe.

du meinst bestimmt diese stelle:
Code:
String command = "INSERT INTO " + C_SensorValueTable.TableName + " (" + C_SensorValueTable.SensorValueSensorID + ", " + 
C_SensorValueTable.SensorValueRecordID + ", " + C_SensorValueTable.SensorValueMeasurementTime + ", " + C_SensorValueTable.SensorValue + ") VALUES (" + sensorID + ", " 
+ recordID_ + ", '" + datetime + "', " + Double.parseDouble(tokens[i]) + ");";

wie sollten denn meine arbeiten in bezug auf dem 'StringBuffer' fortgesetzt werden?

kannst du ein kleines beispiel angeben? wäre sehr nett 😉

gondor(..)


edited by thE_29: abgeteilt - zu störend
 
String sind unveränderlich, das heißt immer wenn du etwas mit einem String machst (was anhängen, was rausschneiden, was ändern...)
erzeugst du ein neues Objekt. Um das zu vermeiden solltest du mit StringBuffer arbeiten. Statt dem '+' dann eben:
Code:
StringBuffer buffer = new StringBuffer("blupp");
buffer.append("bla");
Der Performanceunterschied ist heftig. Siehe hierzu:
http://www.java-forum.org/de/viewtopic.php?t=15006
 
@wildcard

... ja das ist wirklich 'krass'. wenn es daran liegen sollte, bis du mein heutiger held 😉

der aufbau meiner query sollte dann so aussehen, oder?

Code:
        StringBuffer buffer = new StringBuffer("INSERT INTO "); 
        buffer.append(C_SensorValueTable.TableName);
        buffer.append(" (");
        buffer.append(C_SensorValueTable.SensorValueSensorID);
        buffer.append(" ,");
        buffer.append(C_SensorValueTable.SensorValueRecordID);
        buffer.append(" ,");
        buffer.append(C_SensorValueTable.SensorValueMeasurementTime);
        buffer.append(" ,");
        buffer.append(C_SensorValueTable.SensorValue);
        buffer.append(") VALUES (");
        ...

prüfe das mal gleich.

gondor(..)
 
gondor hat gesagt.:
der aufbau meiner query sollte dann so aussehen, oder?
So hatte ich mir das gedacht 😀
Der Vector ist uU auch keine so gute Wahl, da er synchronized ist. Wenn man das nicht braucht sollte man auch nicht
unbedingt Vector benutzen. Dann lieber ArrayList. Wird hier aber weniger das Problem sein denke ich...
 
@wildcard

also, das ist schon schneller geworden. das die gute nachricht.

die schlecht, nicht bedeutend 'viel' schneller. 150 zeilen á 8 werte ca. 15 sek. kann es evtl. auch daran liegen, das die berechnung aus einem parallel gestarteten thread geschieht? diesen habe ich extra schon die prio (9) gegeben.

an der performance kann es eigentlich auch nicht liegen (2GHz, 756ram) wo ist da der bottleneck? oder ist java eh nicht so schnell, auf datenstrukturebene?

please help 🙁

gondor(..)
 
@DP

ja, java ist langsam. langsamer als andere programmiersprachen und schneller als andere programmiersprachen... 😉

akkustikkoppler? hä? was´n das...

hier mal die openConnection:

Code:
     /**
     * Stellt Verbindung zur DB her
     */
    protected void openConnection() {

        //System.out.println("C_DBQuery --> openConnection");

        try {
            /*Treiber laden*/
            Class.forName(C_DB.MySQL_DRIVER).newInstance();
            /* Verbindung aufnehmen*/
            this.mySQL_connection = DriverManager.getConnection(this.mySQL_connection_string, this.mySQL_user, this.mySQL_passwd);

        } catch (Exception ex) {
            /*** Errorhandling ***********************************/
            System.out.println("Error: openConnection (Exception)");
            //cat.error("Error: openConnection (Exception)");
            System.out.println("Exception: " + ex.getMessage());
            System.out.println("ExceptionState: " + ex.toString());
            System.out.println("VendorError: " + ex.getLocalizedMessage());
        }
    }

sieht für mich ganz 'normal' aus... und systemausgaben habe ich auch keine ???:L

gondor(..)
 
komisch ist auch, wenn ein großes file (naja groß? 5000 zeilen) eingelesen wird, kommt es meistens zu einer exception, mit der ich nicht so wirklich etwas anfangen kann:

Code:
Error: openConnection (Exception)
Exception: Unable to connect to any hosts due to exception: java.net.BindException: Address already in use: connect
** BEGIN NESTED EXCEPTION ** 
java.net.BindException
MESSAGE: Address already in use: connect
STACKTRACE:
java.net.BindException: Address already in use: connect
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
	at java.net.Socket.connect(Socket.java:452)
	at java.net.Socket.connect(Socket.java:402)
	at java.net.Socket.<init>(Socket.java:309)
	at java.net.Socket.<init>(Socket.java:124)
	at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:121)
	at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:220)
	at com.mysql.jdbc.Connection.createNewIO(Connection.java:1768)
	at com.mysql.jdbc.Connection.<init>(Connection.java:440)
	at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:400)
	at java.sql.DriverManager.getConnection(DriverManager.java:512)
	at java.sql.DriverManager.getConnection(DriverManager.java:171)
	at de.airbus.arctic.db.mysql.C_DBQuery.openConnection(C_DBQuery.java:160)
	at de.airbus.arctic.db.mysql.C_DBQuerySensor.getSensorID(C_DBQuerySensor.java:498)
	at de.airbus.arctic.measurement.sensor.C_Sensor.getSensorID(C_Sensor.java:95)
	at de.airbus.arctic.measurement.importDB.C_Import.parseData_DateTime(C_Import.java:505)
	at de.airbus.arctic.measurement.importDB.C_Import.run(C_Import.java:371)
	at de.airbus.arctic.gui.dialog.status.C_Dialog_Import.run(C_Dialog_Import.java:693)
	at java.lang.Thread.run(Thread.java:534)
** END NESTED EXCEPTION **

und komisch ist, dass mir in der methode queryUpdate

Code:
while (it.hasNext()) {

                st = this.mySQL_connection.createStatement();
                System.out.println(it.next().toString());
                st.addBatch(it.next().toString());
            }

            int[] execute_batch = st.executeBatch();
            System.out.println("Anzahl Batch-Updates : " + execute_batch.length + "");

bei executeBatch mir eine '1' rausgibt, obwohl er z.B. 100mal addBatch(string) gemacht hat. richtig wäre doch da '100'.

der string sieht folgendermaßen aus:

Code:
INSERT INTO mess_sensor_value (sensor_value_sensor_id, sensor_value_record_id, sensor_value_time, sensor_value_value) VALUES ( 43, 33, '2004-12-12 13:01:03', 15.0 )

warum macht der das?

hm...

gondor(..)
 
Achja und wenn du alle Spalten in der richtigen Reihenfolge befühlst, kannst du dir das sparen, das du vorher alle Spalten angibst!

Bsp.: INSERT INTO mess_sensor_value VALUES( 43, 33, '2004-12-12 13:01:03', 15.0 )
 
Das war als Bsp!

Du mußt bei diesem Insert alle SPALTEN befühlen, also wenn du mehr Spalten hast und dort null Werte normalerweise stehen würden, müßtest du dann hinten ,null,null, ... etc reinschreiben!
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben