Seite 1 von 1
SQLITE blockiert temporär meine GUI
Verfasst: 13. März 2013 20:40
von ulmste
Kurz zu meinem Projekt:
Ich arbeite auf einer embedded Linux platform (icnova base) mit avr32 architektur. Am board, ass Ich dafür verwende, hängt ein tft-Display mit touch-sensor, sowie eine SD-Karte von welcher das embedded linux OS bootet und läuft.
Trotz der wirklick kargen AUsstattung (140MHz Prozessor und nur 64MB Ram), läuft meine QT-ANwendung relativ flüssig und reagiert recht gut. In letzter Zeit versuche Ich einen Zählwert in einer sqlite3 Datenbank auszulesen, zu bearbeiten und wieder zu speichern. Gleichzeitig speichere Ich bei jeder Verarbeitung einen Log-Eintrag in derselben Datenbank, allerdings in einer anderen Tabelle. Dabei handelt es sich um ein eigens konstruirtes WIdget (also eine GUI-Klasse), welche di notwnedige ANzeige und Funktionalität in meine Applikation integriert.
Hier mein Problem:
Bei jedem Schreib-Zugriff friert die GUI für ca. 1 Sekunde ein (Bei Lese-Operation sind keine Auswirkungen erkennbar).
Ich habe bereits auf verschiedenste Weise versucht, die SQL-Anweisungen in einen Thread aus zu lagern. Durch die Verwendung von "QSqlQuery::transaction" und "QSqlQuery::commit" konnte Ich merhere ANweisungen zusammenfassen und dadurch den Effekt verringern, so dass für 4 ANweisungen die GUI nur für 2 Sekunden einfriert. ALlerdings ist auch dies keine zufrioedenstellende Lösung.
Bei verschiedenen tests ist mir aufgefallen, dass die Datenbank per console ohne Probleme bearbeitet werden kann ohne dass die GUI einfriert. Bevor nun allerdings die gesamte SQL-Kommunikation auf ein externes Programm auslagere, wollte Ich mich in diesem Forum nachfragen, ob es jemanden gibt, der vielleicht Erfahrung auf dem Gebiet hat bzw. ob jemand das selbe Problem bereits gelöst hat.
Ich bin für jegliche Hilfe dankbar.
Re: SQLITE blockiert temporär meine GUI
Verfasst: 20. März 2013 13:48
von trendyAndy
Servus Ulmste,
ich hatte ähnliche Probleme (embedded Linux, Sd-Karte) Die Schreibgeschwindigkeit auf SD ist leider sehr viel langsamer als die Lesegeschwindigkeit. Um die Datenbank zu füllen konnt ich mal kurz Kaffee trinken gehen oder mit dem Hund gassi. Ich nutze jetzt eine Memory basierte DB die ich nur beim Beenden auf der Karte sichere und beim Start der Anwendung wieder einlese. Zwischendurch sichere ich immer mal wieder die DB auf der Karte. Dumm nur wenns mal Stromausfall gibt, dann kann es sein dass deine Daten auf der SD nicht aktuell sind.
Was aber auch sein kann ist, dass du ein SQLQueryModel oder irgend ein anderes Model und QTableView nutzt. Daten in die DB rein schreiben geht recht flott, aber bis die in der TableView auf der GUI erscheinen friert die GUI ein.
Wie genau zeigst du die Daten an bzw. welches Model benutzt du?
Gruß
Andy
Re: SQLITE blockiert temporär meine GUI
Verfasst: 20. März 2013 19:43
von ulmste
Hallo Andy,
Ich nutze eigentlich kein spezielles Modell. Ich lese bestimmte querys aus und zeige diese in Text-Labels auf dem verbundenen TFT-Display an an. Wenn ein Ereignis rein kommt, wird die GUI aktualisiert und die SQLITE-DB ebenfalls. Ich hatte das ganze bereits am Laufen mit einer simplen Text-Datei, in die Ich die Werte geschrieben habe. Allerdings habe Ich da das Problem, dass wenn mein board aufgrund eines Stromausfalls abschmiert, die Datei korrumpiert werden kann, so dass diese gar nicht mehr vorhanden ist; um dieses Problem zu lösen, hätte Ich müssen eine Stromausfall-Detektierung einbauen und eine Pufferbatterie einbauen, die das system so lange halten kann, dass es bei einem detektierten Stromausfall einen Shutdown machen kann ,damit die Daten sicher gespeichert werden.
Darum habe Ich dann das ganze auf SQL gewechselt. Mir scheint das istn icht so anfällig auf Korruption. Leider habe Ich diese Latenzen beim Schreiben. Schreibt man allerdings über die Linux-Konsole parallel zur laufenden QT-ANwendung in die SQLITE-Datenbank tauchen diese Latenzen nicht nicht auf, die GUI reagiert durchgehend ohne Verzögerungen. Deshalb habe Ich mir schon überlegt die SQL-Geschichte in einen externen Prozess aus zu lagern (C-Programm).
Kurz zum Zweck: Ich habe in den Kernel eine Art GPIO-COunter integriert. DIeser Counter zählt im sysfs jeden Impuls an einem definierten GPIO-PIN mit und speichert den aktuellen Zählwert im sysfs. Da der Sysfs aber nur temporär im RAM-SPeicher läuft brauche ICh also eine Möglichkeit diesen Zählwert totalitär irgendwo im Filesystem von linux remament zwischen zu speichern; dafür verwende Ich aktuell die SQLITE-DB. Der einzige andere Weg, wäre auf der Hardware-Seite: Speichern des Zählwertes in einem eeprom. Allerdings will Ich jeden Tag zu einer gewissen Zeit den aktuellen Zählwert in eine Art Log-Datei abspeichern, wofür SQLITE wieder hervorragend geeignet ist. Mein Problem ist hier nicht, dass SQLITE lange braucht um in die DB zu schreiben, das wäre mir im Grunde egal, das Problem ist, dass während des Schreibprozesses meine GUI blockiert wird.
Ich habe auf meinem board auf direkt eingbauten Flash-Seicher zur Verfügung. Wenn die Latenzen beim Schreiben der DB nur von der langsamen Geschwindigkeit der SD herrühren, dann könnte Ich auch versuchen die SQLITE-DB auf dem flash-speicher unter zu bringen. Allerdings, wie bereits erwähnt, das Schreiben in die DB aus der Linux-Konsole bei laufender GUI, funktioniert ohne die GUI zu blockieren. Deshalb gehe Ich hier eher von einem QT-Problem aus, oder eben von meiner Unwissenheit SQL-Befehle richtig in einen Thread von QT aus zu lagern, so dass die GUI nicht mehr blockiert wird. Ich würde ungern die SQLITE-Geschichte aus meiner QT-Applikation auslagern, da es sehr viele Vorteile hat direkt mit der SQL-DB kommunizieren zu können (auch wegen des Klassen-Modells von Qt). SOllte es allerdings der einzige Weg sein, um die SQL-DB zu handhaben, ohne dass meine GUI blockiert wird, dann werde Ich wohl diesen Weg gehen müssen.
Die ganze GUI läuft auf einem TFT-DIsplay, der an meinem Grasshopper-Board hängt; die Anzeige erfolgt also mit dem QT-framebuffer treiber.
Gibt es überhaupt einen Weg in QT die SQL-Querys zum Schreiben in die DB so in einen Thread auszulagern, dass die GUI nicht mehr blockiert wird?
Re: SQLITE blockiert temporär meine GUI
Verfasst: 20. März 2013 22:49
von Christian81
Wie genau schreibst Du in die DB - kannst du mal ein minimales Beispiel geben wo Du zeigst wie dein Problem auftritt? Ich hab mit SQLite kein Problem...
Re: SQLITE blockiert temporär meine GUI
Verfasst: 21. März 2013 21:02
von ulmste
Hallo Christian81,
Ich habe test-weise eine Thread-Klasse erstellt, in der ich die Datenbank öffne und mit einem Timer jede Sekunde 4 Querys durchführe. Diesen Thread starte Ich beim Laden der GUI um heraus zu finden, ob die AUslagerung in einen Thread die GUI nicht mehr blockiert. Vorher hatte Ich die SQL-Befehle direkt in die GUI-Klasse implementiert; dabei sit mir dass Blockierne der GUI das erste mal aufgefallen. Wenn irgendwie möglich wäre mir eine Lösung am Liebsten, bei der Ich die SQL_ROutinen zumindest in einem QThread verwednen könnte.
Hier die Details zu meinem COde.
Datenbank öffnen:
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("counter.sql");
//TImer-Routine:
tPolling->stop();
if (db.isOpen())
{
db.transaction();
QString strQuery = "INSERT INTO log VALUES (1002625,10002,2013,03,01,15,30,20,255,258,2365,23658,23659)";
QSqlQuery query(db);
query.prepare(strQuery);
query.exec();
query.prepare(strQuery);
query.exec();
query.prepare(strQuery);
query.exec();
query.prepare(strQuery);
query.exec();
db.commit();
}
tPolling->start();
Die 4 querys blockieren für ca. 2 Sekunden meine GUI.
Ich habe in verschiedenen Foren gelesen, dass dies ein Bug von QT ist. Andererseits könnte es auch sein, dass mein board mit 64 MB RAM und 140MHz CPU es nicht besser kann, allerdings spricht die Tatsache dagegen, dass jegliche querys aus der Linux-Console ausgeführt die parallel geöffnete GUI in keinerlei Weise verlangsamen. Ein hardware-Wechsel auf eine leistungsfähigere platform wäre durchaus möglich.
Welche Platform verwendest du? Wie sieht dein COde zum Schreiben in die Datenbank aus? Wie ist die Struktur in der Applikation (GUI, Threads)?
Re: SQLITE blockiert temporär meine GUI
Verfasst: 21. März 2013 21:17
von trendyAndy
Ich kenne das Grasshopper board nicht, habe aber unter anderem einen Raspberry pi bei dem ich eben mit den sehr schlechten Zugriffszeiten auf die SD-Karte zu kämpfen hatte. Da gings aber um tausende Einträge. Aber 4 Anweisungen und 2 Sekunden sind echt langsam. Der Raspi hat auch mehr power wie das Grasshopper. Wieso machst du das prepare da rein?? Die query kannst du direkt ausführen. Das prepare nimmst du ja nur wenn du eine bindvalue brauchst.
Gruß
Andy
Re: SQLITE blockiert temporär meine GUI
Verfasst: 21. März 2013 22:29
von ulmste
Hallo Andy,
die direkte Anweisung brucht länger. Durch das "transaction" und das "commit" am Ende, kommt man von ca. 4 Sekunden auf 2 Sekunden herunter. In verschiedenen Foren wird immer wieder darauf hingewiesen, dass dafür das prepare verwendet werden muss, also habe Ich es auch verwendet.
Kannst du mir die Daten deines Boards geben, damit Ich einen Referenz-Wert habe? Hattest du bei dem Board mit deiner SD-KArte keine solchen Latenzen mehr?
Gruß
Stefan
Re: SQLITE blockiert temporär meine GUI
Verfasst: 22. März 2013 09:15
von Christian81
Das db.open() machst Du aber nicht im Timer-Slot, oder?
Eine Idee wäre noch, das QSqlQuery-Objekt als Member (pointer in deinem Fall) anzulegen so dass dieses nicht immer erzeugt werden muss - das hat bei mir einmal zu einer Performance-Einbuße mit Informix geführt. Dann würde ich mal ein paar Logausgaben reinbauen um zu schauen wo genau er die Zeit verbringt. Natürlich die Ausgaben mit Millisekunden...
Ansonsten fällt mir da nicht viel zu ein außer, dass sqlite eine einfache API hat die man auch direkt benutzen kann

Re: SQLITE blockiert temporär meine GUI
Verfasst: 22. März 2013 12:20
von trendyAndy
Hallo Stefan,
der Raspi hat 512Mb RAM. Ich habe ihn aufgeteilt in 256MB RAM und 256MB Grafikspeicher. Man kann ihn bis zu 950MHz hoch takten und er läuft mit nem Debian auf SD-Karte. GPIO usw. hast du natürlich auch. Ich habe den QtCreator auf dem Raspi laufen und kann direkt mit dem Raspi entwickeln. Macht aber nicht wirklich Sinn denn der braucht schon mal ne Weile um zu kompilieren...
Schaust du hier:
http://www.raspberrypi.org/
Das Teil kostet nur knappe 30€, ist aber fast immer vergriffen und man kann schon mal 8 Wochen drauf warten.
Hier mal ein Beispiel aus meinen Anfängen als die DB noch nicht :memory: war:
Code: Alles auswählen
if(db->isOpen())
{
if(!db->transaction())
return false;
QSqlQuery query = db->exec();
for(int i = 0; i< .......)
query.exec(QString("insert into Table values(NULL, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12)").arg(.......));
}
db->commit();
Wie gesagt das war am Anfang als ich mit Datenbanken begonnen habe und die DB als Member angelegt hatte. Mittlerweile sieht das alles anders aus. Aber wenn ich das richtig verstanden habe, dann schreibt er nicht die einzelnen querys in die DB sondern eben alles erst mit dem commit() . Das prepare nutze ich wirklich nur wenn ich was in die DB schreiben will, was man nicht in den Querystring rein bekommt, z.B. einen blob. In deinem Fall würde ich sagen du brauchst das prepare nicht, kann aber auch falsch liegen.
In irgend einem Forum habe ich dann folgende Variante entdeckt und durchgängig ungesetzt:
Code: Alles auswählen
bool Datenbank::openDB()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE","MyDB");
db.setDatabaseName(":memory:");
return db.open();
}
Und überall wo ich eine Query ausführe mache ich da so:
Code: Alles auswählen
QSqlQuery query(QSqlDatabase::database("MyDB"));
query.exec("INSERT ......");
query.clear();
Ob das jetzt der optimale Weg ist weiß ich nicht. Jedenfalls klappts ganz gut bis jetzt
Vielleicht kann ja noch ein DB Experte was zu den einzelnen Varianten sagen???
Gruß
Andy
Re: SQLITE blockiert temporär meine GUI
Verfasst: 24. März 2013 14:37
von ulmste
Hallo ANdy,
könnte es sein, dass mit deinem Ansatz (":memory:"), die DB nur im RAM-Bereich läuft? Es funktioniert zwar alles, die GUI friert nicht mehr ein, doch wenn Ich mit der Konsole in meiner SQL-Datenbank kontrollieren will, so sind die querys dort nicht vorhanden.
Ich verwende ein ext4-filesystem, auf dem meine Datenbank liegt. Welches filesystem verwendest du für deine Lösung?
MFG
Stefan
Re: SQLITE blockiert temporär meine GUI
Verfasst: 24. März 2013 19:57
von trendyAndy
Hallo Stefan,
genau das ist der Trick an der Sache, ich habe eine DB mit 5000 oder mehr Einträgen. Weil eine query auf der SD Karte so lange gebraucht hat, lese ich die DB beim Start der Applikation in eine memory basierte DB ein. Dadurch sind die querys schnell und ich habe keine Probleme mehr mit ewig langen Wartezeiten. Zwischendurch sichere ich dann immer wieder die gesamte memory DB auf die SD. Das einzige Problem ist eben wenn man Stromausfall hat und die memory DB noch nicht auf der SD gesichert ist. Bei mir spielt das keine so große Rolle wenn mal wenige Datensätze fehlen.
Gruß Andy