Ucanaccess Performance Probleme


Habedere1983

Grünschnabel
Hallo zusammen,

Ich habe mein erstes Javafx Programm geschrieben, welches mit ucanaccess auf eine Accessdatenbank zugreift. Alles funktioniert soweit gut, nur lässt die Performance zu wünschen übrig. Ich habe mich an ein Tutorial gehalten und gehe bei jedem Sql-Befehl wie folgt vor:
Connection zur DB herstellen, sql-Befehl ausführen, connection schließen.
Wenn ich im Firmennetzwerk arbeite ist das noch akzeptabel. Vom Homeoffice aus unzumutbar mit ladezeiten bis zu 20s.

Könnt ihr mir einen Tipp geben, wie das schneller geht.

Meine Vorstellung wäre bei Programmstart einmalig die DB Verbindung herzustellen, dann 8 Stunden arbeiten und bei beenden des Programms die connection schließen. Wann darf und muss man die connection trennen? Sorry für die dumme Frage...

Besten Dank
Thomas
 

ComFreek

Mod | @comfreek
Moderator
Wenn ich im Firmennetzwerk arbeite ist das noch akzeptabel. Vom Homeoffice aus unzumutbar mit ladezeiten bis zu 20s.
Laut deiner Beschreibung habe ich das Gefühl, dass der Verbindungsaufbau der Bottleneck ist und nicht das Query mit den Ergebnisdaten. Oder wie groß sind deine Ergebnisdaten? Wie viele Spalten/Zeilen mit welchen Datentypen?

Dann muss es wohl auf der Verbindung zum Firmennetzwerk irgendein Bottleneck geben. Kannst du das vielleicht mit dem IT-Support mal debuggen?

Meine Vorstellung wäre bei Programmstart einmalig die DB Verbindung herzustellen, dann 8 Stunden arbeiten und bei beenden des Programms die connection schließen. Wann darf und muss man die connection trennen? Sorry für die dumme Frage...
Das kannst du schon so machen. Die Verbindung kannst du immer trennen. Ob du sie wirklich trennen musst, bezweifel ich. Das gehört sicherlich zum guten Stil, damit du den Verbindungspool nicht unnötig groß hälst. Wahrscheinlich ist das DBMS sowieso so programmiert, dass es einen Timeout gibt, wenn du innerhalb von X Zeiteinheiten nichts mehr schickst.
 

Habedere1983

Grünschnabel
Hallo, danke für die rasche Antwort. Ich denke ich muss hier etwas ausholen. Ich bin absolut nicht vom IT Fach. Schreibe privat eine Software die in der Firma von der IT nicht gewünscht, aber geduldet ist. Folglich null IT Support. Es werden ca. 10 Personen die Software gleichzeitig benutzen.
Wenn ich die Verbindung jetzt dauerhaft offen lasse, was kann im schlimmsten Falle passieren? Datenverlust? Abstürze? Zerstören der Datenbank? Warum muss eine Verbindung zur Datenbank Grundsätzlich getrennt werden?

Vorhin habe ich das offen lassen der Verbindung getestet im Homeoffice. Ergebnis ist eine schnelle Verbindung und kaum Wartezeiten... Also liegt es wirklich an der ersten Verbindung zur DB.

Die größte Tabelle in der DB hat ca 5000 Zeilen aktuell und 20 Spalten. Die ganze Accessdb hat ca. 7mb
 

ComFreek

Mod | @comfreek
Moderator
(1) Wenn ich die Verbindung jetzt dauerhaft offen lasse, was kann im schlimmsten Falle passieren?
(2) Datenverlust?
(3) Abstürze?
(4) Zerstören der Datenbank?
(5) Warum muss eine Verbindung zur Datenbank Grundsätzlich getrennt werden?
In der Reihenfolge:
  1. Gar nichts. Wenn du aber Verbindungen immer neu aufmachst und alte nicht schließt (und die sich innerhalb eines Timeouts noch nicht geschlossen haben), dann könnte es zu Performanceeinbußen kommen. Das wirst du bei 10 Nutzern sicher nicht sehen.
    Du solltest jedoch keine Locks unendlich lang halten. Wenn du nicht weißt, was ein Lock ist, benutzt du wohl keine :)

  2. Nein.
  3. Nein - außer bei sehr vielen Verbindungen. Ohne nennenswerte Kenntnisse würde ich auf min. > 500 tippen.
  4. Aus "sanity" Gründen. Für jede Verbindung werden Verbindungsdaten seitens des Datenbankservers gehalten. Die werden beim Trennen freigegeben.
Die größte Tabelle in der DB hat ca 5000 Zeilen aktuell und 20 Spalten. Die ganze Accessdb hat ca. 7mb
Das ist eine sehr kleine Größenordnung und kann die 20s Wartezeiten eigentlich nicht erklären.
Ich würde vielleicht mal mit Wireshark prüfen, wie lange die einzelnen Pakete brauchen für den Verbindungsaufbau.
Aber du kannst die Verbindung fürs Erste auch einfach halten.
 

Habedere1983

Grünschnabel
Super, die Antworten helfen mir bestimmt weiter. Muß ich denn in meinem Fall die Verbindung zur Datenbank überhaupt manuell trennen, oder geschieht dies automatisch beim schließen der Applikation?
 

ComFreek

Mod | @comfreek
Moderator
Muß ich denn in meinem Fall die Verbindung zur Datenbank überhaupt manuell trennen, oder geschieht dies automatisch beim schließen der Applikation?
Das kann durchaus auch von der Wahl deiner Programmiersprache und des SQL-Drivers abhängen. Wenn du sowas wie RAII in C++ hast und dein Verbindungsobjekt Scope verliert, dann kann es sein, dass sein Destruktor die Verbindung schließt. Aber das kann auch weit hergegriffen sein, ich habe mit SQL-Drivern in C++ noch nie gearbeitet.

Aber ich sehe insgesamt nicht, wo das Problem ist, einfach die Verbindung zu schließen ;)
 

Technipion

Erfahrenes Mitglied
Meiner Erfahrung nach sind wir Programmierer einfach schrecklich darin, Bottlenecks zu erahnen. Ich würde hier tatsächlich einfach mal ein "Benchmark" laufen lassen. Hier ist ein kleiner Codeschnipsel, der dafür angepasst werden kann:
Java:
// Benchmark.java

import java.time.*;


public class Benchmark {
    public static void main(String[] args) {
        Instant start_connectDB = Instant.now();
        for (int i = 0; i < 10; i++) {
            connectDB();
        }
        Instant end_connectDB = Instant.now();
        Duration d_connectDB = Duration.between(start_connectDB, end_connectDB);

        Instant start_runDBcommand = Instant.now();
        for (int i = 0; i < 10; i++) {
            runDBCommand();
        }
        Instant end_runDBcommand = Instant.now();
        Duration d_runDBcommand = Duration.between(start_runDBcommand, end_runDBcommand);

        System.out.println("Connecting to DB took "
                           + d_connectDB.dividedBy(10).toMillis()
                           + " ms");
        System.out.println("Running DB command took "
                           + d_runDBcommand.dividedBy(10).toMillis()
                           + " ms");
    }

    private static void connectDB() {
        // connect to DB
        // disconnect from DB

        // simulate behaviour --------------------------.
        // remove this later                         // |
        try {                                        // |
            Thread.sleep(100);                       // |
        } catch (InterruptedException e) {           // |
            System.out.println("You woke me up :("); // |
        }                                            // |
        // ---------------------------------------------'
    }

    private static void runDBCommand() {
        // connect to DB
        // run DB command
        // disconnect from DB

        // simulate behaviour --------------------------.
        // remove this later                         // |
        try {                                        // |
            Thread.sleep(110);                       // |
        } catch (InterruptedException e) {           // |
            System.out.println("You woke me up :("); // |
        }                                            // |
        // ---------------------------------------------'
    }
}
Du musst nur in den Funktionen connectDB() und runDBCommand() den Teil hier ergänzen:
Connection zur DB herstellen, sql-Befehl ausführen, connection schließen.
Danach weißt du
a) wie lange es dauert die Verbindung zu öffnen/schließen
b) wie lange es dauert deinen Befehl zu verarbeiten
und kannst dein Programm entsprechend anpassen.

Gruß Technipion

PS: Da ich kein Java-Profi bin, immer her mit Verbesserungsvorschlägen.