Out of Memory Fehler - Große Datenbankabfragen

Schrödi

Mitglied
Hallo zusammen,

ich bin bin relativ neu im Bereich Java (komme aus der php Programmierung).
Ich möchte Daten aus einer Datenbank abfragen (z.Z. ca 100000 Datensätze, steigend), um diese später noch zu bearbeiten und auszugeben (wie die Ausgabe aussehen soll weiß ich bisher noch nicht, vielleicht mittels Zwischenablage, oder CSV Datei).
Soweit bin ich ja auch noch nicht. Der Fehler tritt ja schon bei der Abfrage auf. Ich möchte die Daten in ein Array schreiben und nutze dazu folgende Funktion:

Code:
    public String[][] query_into_array2(String query) {
        Statement st = verbinde_datenbank();


        try {
            ResultSet rs = st.executeQuery( query );

            int rows = anzahlZeilen(rs);
            int cols = anzahlSpalten(rs);

            String[][] antwort = new String[rows][cols];

            int i = 0;
            rs.first();
            while( rs.next() ) {
               for (int j = 0; j < cols; cols++){
                    antwort[i][j] = rs.getString( j );
               }
               i++;
            }

           trenne_datenbank(rs, st);

            return antwort;
        }
        catch (SQLException e) {
            String ErrorMessage = e.getMessage();
            System.out.println("SQL Fehler: " + ErrorMessage);
        }

        return null;
    }

Die MySQL Tabelle sollte OK sein. Laut MySQl ist sie ca. 10 Mb groß.

Wie geht man mit großen Datenmengen bei Java um? Kann man überhaupt mit so großen Datenmengen umgehen ohne das MemoryLimit stetitg zu erweitern?

Gruß Schrodi
 
10 mb ist unproblematisch.
Bei Grössen im Bereich >1 GB sind spezielle Überlegungen nötig, da herkömmliche ApplicationServer nicht für solche Anforderungen ausgelegt sind.

Grundsätzlich sollten die gängigen Datenbankfeature voll ausgenutzt werden, also beispielsweise das Resultset dbseitig so weit wie möglich einzuschränken.

Du könntest überlegen, ob ein 2-dimensionales Array der richtige Speicherort ist. Je nachdem was mit den Daten passieren soll sind vielleicht Listen oder ähnliches sinnvoller.
 
Mal ein Bischen offtopic:
Das Trennen der DB Connection sollte in einem finally Block erfolgen. Im
Fehlerfall bliebe die DB Anbindung ansonsten geöffnet
 
Code:
Two JVM options are often used to tune JVM heap size: -Xmx for maximum heap size, and -Xms for initial heap size.

Beispiel:
java -Xms128m -Xmx256m MeinProgramm

Diese Aufruf würde deine Application mit 128mb starten und bis maximal 256mb wachseln lassen.

EDIT: Außerdem solltest du in Schleifen die oft durchlaufen werden darauf achten das, dass nicht mehr verwendete Referenzen gelöscht werden.

Negativ Beispiel:
Java:
package de.tutorials.johannes7146;

import java.util.ArrayList;

public class OutOfMemory {

    public static void main(String[] args) {
        //Negativ Beispiel:
        ArrayList<Integer> liste = new ArrayList<Integer>();

        for (int i = 0; i < 2000; i++) {
            hinzufuegen(liste);
        }

    }

    private static void hinzufuegen(ArrayList<Integer> liste) {
        for (int i = 0; i < 2000; i++) {
            liste.add(new Integer(i));
        }
    }
}
 
Zuletzt bearbeitet:
Servus,
danke erstmal für so viele Reaktionen.

@ Franz Degenhardt
Die 1GB Grenze werde ich volumenmäßig wohl nicht sprengen.
Die Abfragen sollen variabel erfolgen, gesteuert durch den User. Einschränkungen durch mich sind daher nur bedingt möglich, Wenn der User alle Daten benötigt (Auswertungen über Auftragsabläufe, z.B. der Workflow eines ganzen Jahres), müssen alle Datensätze verfügbar sein.
Die Listen (oder ähnliches), die du angesprochen hast sind mir neu. Muss mich deshalb erst einlesen. Wird aber meine nächste Lektüre werden.

@ Markus
Das werde ich ändern. Habe nicht dran gedacht, dass die Verbindung noch offen ist, wenn der try Block abgebrochen wird.

@ zeja
Das ist mein ZählMethode.

Code:
public int anzahlZeilen(ResultSet ergebnis) {
	try {
	    int c = 0;
	    while(ergebnis.next())
		c++;
	    return c;
	}catch(SQLException sqlex) {
	    return 0;
	}
    }

@ Johannes7146
Ist die Speichererweiterung auch bei einem Webstart möglich? Ich arbeite mit Netbeans. Hier habe ich schon nach einer Möglichkeit gesucht, den Speicher zu erweitern; habe aber nichts gefunden. Wo diese Einstellungen zu finden sind, wird aber mit Sicherheit auch Google verraten.

Bei deinem Beispiel ist für mich leicht zu erkennen, welche Referenzen du meinst. Bei meiner Funktion sehe ich aber nicht die Lösung. (Ab und zu ist für mich ein Wink mit dem Zaunpfahl nötig :-), besonders zu späterer Stunde).

Gruß schrodi
 
Hmm ich halte das bei der von dir beschriebenen Zahl für etwas Problematisch ein Scrollable ResultSet zu verwenden. Ich weiß nicht wie das dort mit der Speicherauslastung aussieht.

Wenn du auf ein Array für deine Zeilen verzichtest und stattdessen eine ArrayList verwendest, ist das Zählen der Zeilen auch nicht mehr nötig. (Ansonsten solltest du über ein Query mit SELECT COUNT zählen).

Dazu wäre es noch interessant wie du dein Statement erstellst und zu welchem Datenbanktyp du dich verbindest.
 
Ui und das auf ner Uni-Seite *brr*

Deutsche Methodennamen sind ja schonmal richtig pfui... und die ordentliche Behandlung mit finally-Blöcken fehlt auch in der Quelle leider gänzlich.

Was soll das ganze Programm denn letzendlich können? Baust du nur einmal eine Verbindung auf und rufst die Daten ab oder geschieht der mehrfach und gleichzeitig von verschiedenen Nutzern?

Datenbankabfragen haben leider in Java ein hohes Fehlerpotential und es kommt ein wenig darauf an was man damit vorhat, ob man nicht eventuell eine Bibliothek benutzt die das ganze vereinfacht.

Normalerweise sollte es so in der Art aussehen:

Java:
try {
final Connection con = createConnection();
try {
    final Statement stmt = con.createStatement();
     try {
         final ResultSet rs = stmt.executeQuery();
         try {
                // Auslesen aus dem ResultSet
         }
         finally {
              rs.close();
         }
    }
     finally {
        stmt.close();    
     }
}
finally {
   con.close();
}
}
catch(SQLException e) {
    // Behandeln der Exception oder zumindest
    // e.printStackTrace()
}

Wie du siehst ist der Code nicht gerade schön und lesbar. Dafür gibt es die genannten Bibliotheken wie z.B. http://www.tutorials.de/forum/java-...tenbankzugriff-mit-springs-jdbc-template.html oder commons DbUtils
 
oh. Ich dachte mit der Uni Seite hätte ich eine zuverlässige Quelle. Scheinbar doch nicht. Dein Code sieht da doch etwas logischer aus.

Das Tool soll von mehreren Usern parallel verwendet werden.

Von diversen Frameworks für Datenbankzugriffe habe ich auch schon gelesen, ich dachte jedoch, dass es etwas übertrieben wäre für meine wenige DBZugriffe ein Framework zu verwenden. Werde es mir jetzt aber doch mal ansehen.

Morgen werde ich erst einmal eure Hinweise beherzigen und testen.

Gruß schrodi
 

Neue Beiträge

Zurück