QTableView mit riesigen Datenmengen live befüllen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

Hallo,

ich bin gerade bei den Planungen für mein nächstes Projekt und bin mir noch nicht ganz sicher wie ich ein QTableView Element mit Daten füttern soll. Einerseits besteht die Möglichkeit per Sqlite-Datenbank und dem QSQlTableModel was mir aber nach einigen Tests für die Aufgabe (Live-Darstellung von immer größer werdenden Messdatensätzen) zu langsam vorkommt.
Die Daten können extrem groß werden, es sollte also nicht wie hier, alles aufeinmal eingelesen werden, sondern nur der Bereich der gerade angezeigt wird.

Bei meinen Recherchen bin ich auf PyTables gestoßen. Dies mit einem QTableView-Element zu verbinden, wäre wohl für meine Aufgabe die beste Lösung.

Hat jemand von euch schon einmal etwas in diesem Zusammenhang gemacht, oder hat vielleicht jemand Alternativvorschläge wie man mit ganz großen Datensätzen in PyQt Live-Darstellungen umsetzt?

(Ein anderes Problem ist, dass beim QSqlTableModel bei jedem neuen Datensatz, die ganze Tabelle neu eingelesen wird, das kann bei kleinen Mengen egal sein, in meinem Anwendungsfall wäre das ein absolutes No-Go.. aber vielleicht lag das auch nur an mir? Kann man das irgendwie umgehen, ohne gleich das ganze Model annähernd selbst zu schreiben?)
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

Da noch keine Antworten eingetroffen sind, ergänze ich meine Frage um ein anderes Problem, vielleicht weiß ja jemand bei diesem einen Rat:

Mein QTableView springt immer bei jedem neuen Element dorthin, ich will aber während dem Einfügen von Elementen auch irgendwo in der Liste hinscrollen können ohne dass es immer wieder zurückspringt, abgesehen davon sollte es wenn ich ganz nach unten scrolle aber auch wieder den neuen Datensätzen folgen.

Vom Prinzip her genau gleich wie es die X-Terminals unter Linux, also z.B. "Gnome Terminal" oder "Konsole", handhaben.
...
User
Beiträge: 116
Registriert: Mittwoch 23. Dezember 2009, 20:22

Hä?

Ich habe ein SQLite-Datenbank von was um die 100mb
Ich merke kaum das die erst eingelesen wird.
Das TableView läd dann aus dem Model immer nur was angezeigt wird.
Darum wird ja auch der Scrollbalken erst mit der Zeit immer kleiner, je weiter du gescrollt hast.

Ich weiß nicht in welchen Größenordnungen du dich bewegst, aber ich halte das auch schon für eine beachtliche Datenmenge, und hatte damit kein Problem.

Ansonsten kannst du auch ein QSqlQueryModel dem zu grunde legen.
Und entsprechend der gewünschten Datensätze den Query ändern.

So kannst du die geladene Datenmenge vieleicht begrenzen.
Musst dann halt überlegen wie du es machen willst, das genau das im Query steht, was du grad anschaun willst...


lg,
...
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

Hallo ...
es handelt sich um Datenmengen im Bereich von 10-50 Gigabyte (im Extremfall auch bis zu 100GB), die sich hier in der Datenbank bzw. am Speicherort befinden. Von diesen Daten sollte, immer nur Schritt für Schritt das eingelesen werden was angezeigt wird.
Meine erste Überlegung war eben ein QTableView mit einer eigenen Model-Klasse von QAbstractTableModel abgeleitet und dort den Zugriff zu realisieren.

Die Frage ist eben ob eine Datenbank hier nicht bremsend wirkt und es besser wäre die Daten auf andere Weise abzulegen.

Es handelt sich übrigens um pcap-Daten, es bestünde also durchaus die Möglichkeit das libpcap-eigene Dateiformat zu verwenden und diese abzuspeichern, wobei ich nicht wirklich sicher bin ob sich dieses für solch große Datenmengen überhaupt eignet. Bei diesen Überlegungen kam ich wieder auf die Idee mit dem HDF zurück..

Hat jemand von euch schon mal unter Python mit so riesigen (>10GB) Datenmengen "herumhantiert"?
Würde gerne wissen, wie Ihr das angegangen seid und ob es sich lohnt hier auf HDF (bzw. h5py zurückzugreifen.)
...
User
Beiträge: 116
Registriert: Mittwoch 23. Dezember 2009, 20:22

Ich habe zwar noch nicht mit solchen Datenmengen hantiert, aber...
Ich schätze das da SQLite ohnehin einige Zeit benötigt, um auch nur kleine Querys zu bearbeiten...


Aber wie ich schon voher sagte: Es gibt ja auch QSqlQueryModel.

Da sendest du ein normales SQL-Query, und die Rückgabe - ja auch in Form von einer Tabelle - ist dann dein Model.

Den Query kannst du ja beliebig ändern...
Ansonsten kannst du auch direkt über QSql einen Query schicken, und die Daten manuel in dein Model einfügen.
Den Grundstock kannst du ja schon mit dem QSqlQueryModel erledigen.
Mach das Modell einige 10 - 100 Datensätze in jeden bereich größer, dann hast du n bisschen Puffer, und jedesmal wenn du Scrollst, schickst du halt n neuen Query, der dir die x nächsten Datensätze holt, und fügst das in dein Model ein, während du du die x letzten rauswirfst.

Leider habe ich mit dem Manuelen befüllen von Models keine erfahrung, aber ich denke das müsste so gehn...

SQLite unterstützt glaub ich auch die verwendung mehrerer Dateien als eine Datenbank.
So könntest du versuchen, nur die benötigten Dateien in deine Datenbank zu laden... aber hier frag mich nicht wie... Ich bin mir aber sicher davon im Web gelesen zu haben...

Ich Denke das eine Datenbank ansich nicht das Falscheste ist - immerhin sind diese dazu entworfen große Datenmengen zu Speichern.

lg,
...

EDIT: Mh - h5py sieht auch interessant aus...
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

Ich habe nun ein eigenes Model mit Zugriff auf SQLite entworfen, das ganze ist aber Performance-mäßig völlig funktionsunfähig. Vielleicht mache ich ja etwas grunsätzliches falsch.

Ich arbeite mit verschiedenen Pipes gemäß http://code.activestate.com/recipes/496 ... ded-pipes/ angefangen bei einer Pipe bzw. einem Faucet welches die Netzwerkdaten per pypcap einliest, sie dann an eine Decodierpipe weitergibt, welche die Daten nach erfolgreichem Parsen wiederum an eine Datenbankpipe weitergibt und sie in die SQLite-DB einfügt.

Der Grund warum ich das gemacht habe war der, dass man bei pysqlite nur aus einem Thread auf ein Handle der Datenbank zugreifen kann, ich brauchte also einen Datenbankthread der alle Aufgaben erfüllen kann... deshalb die Pipe an die alles weitergereicht wird.

Das Problem ist nun, dass meine von QAbstractTableModel abgeleitete Klasse vor allem für die RowCount() und die data() Funktion viel zu lange braucht und dadurch das ganze Qt-Programm fast gänzlich blockiert wird.

Mein nächster Versuch war dann, nur alle paar Sekunden die Zeilenzahl auszulesen, sie statisch abzulegen und für die Daten einen Cache zu basteln, dass immer schon die angrenzenden Daten eingelesen werden, bevor überhaupt dorthin gescrollt wird.
Trotzdem braucht diese Funktion viel zulange und das ganze Programm hängt.
Ich denke langsam, dass mein Ansatz gänzlich falsch ist und ich die Model-View-Architektur falsch umsetze.

Das hier ist die Datei "packetmodel.py" die das Model enthält: http://paste.pocoo.org/show/186300/
Und hier noch die Datei "datamgr.py" welche die oben erwähnte Pipe enthält, welche die Daten in die Datenbank einfügen soll: http://paste.pocoo.org/show/186296/

Hat jemand eine Idee oder einen Alternativvorschlag wie ich möglichst effektiv gleichzeitig einen Socket-Zugriff (pypcap) der permanent Daten einliest und parallel dazu ein Model für ein QTableView realisieren kann, welches ohne Performance-Einbußen die Daten anzeigt.

Danke!
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

philistion hat geschrieben:Hat jemand eine Idee oder einen Alternativvorschlag wie ich möglichst effektiv gleichzeitig einen Socket-Zugriff (pypcap) der permanent Daten einliest und parallel dazu ein Model für ein QTableView realisieren kann, welches ohne Performance-Einbußen die Daten anzeigt.
Kannst Du bitte nochmal genauer beschreiben was Dein Programm machen soll? Willst Du zeitgleich die pcap-Daten vom Netzwerk nativ erhalten (sniffen) und in die DB schreiben/lesen? Ich bin aus Deiner Beschreibung leider nicht ganz schlau geworden.

Ein paar Anmerkung habe trotzdem zu Deinem Setup:

50-100GB an Daten/Backendwahl:
Ein Frage vorweg, nutzt oder brauchst Du die Relationen später, die Dir ein SQL-DBMS bietet? Wenn ja, brauchst Du eine skalierbare Lösung, die den Verwaltungsaufwand zeitnah erschlagen kann (Wie hoch ist das Datenaufkommen/Zeit? Kann Dein jetziges System das noch ohne Drops abarbeiten?). Sqlite ist da nicht die beste Wahl, da gerade Inserts für DBs>1GB extrem langsam werden. Bis hin zu einem Oracle/DB2-Cluster wäre hier alles denkbar.
Solltest Du die Relationen nicht brauchen (danach sieht Dein Code derzeit aus), ist eine performante "Datenhalde" das Mittel der Wahl. Beispiele hierfür wären key-value DBs. Diese sind bieten meist auch eine hohe Skalierbarkeit (bei vgl. geringeren Anforderungen gegenüber den relationalen DBMSen). Das HDF5 kenne ich leider nicht, in wie weit dies Deinen Anforderungen gerecht wird, beantwortet Dir sicherlich die Spezifikation.

Python:
Für mich hört sich Dein jetziger Ansatz so an, als wolltest Du viele Dinge parallel in Threads abarbeiten. Das geht in Python leider nicht, wie Du es vllt. von anderen Sprachen her kennst, da Python die Ausführung von Threads mittels des global interpreter lock (GIL) koordiniert und die Ausführung von Pythoncode auf einen aktiven Thread beschränkt. Braucht ein Aufruf innerhalb eines Threads zu lange, werden die anderen mit ausgebremst. Ausnahme sind hier viele low-level-Funktionen (z.B. time.sleep) die den GIL freigeben. U.a. gibt auch der Großteil der PyQt-Bibliothek den GIL frei. (Als Tip: Alles was Qt nahe threaded passiert würde ich eher mit QThread umsetzen, hat den Vorteil, dass Du das Eventsystem nutzen kannst)
Brauchst Du allerdings viel Pythoncode in den Threads, bleibt das GIL-Problem bestehen. Evlt. hilft Dir dann das [mod]multiprocessing[/mod]-Modul weiter.
Falls das alles nicht hilft, wirds hässlicher, da Du dann evtl. Teile Deiner Applikation in c auslagern oder gar über einen Wechsel der Sprache nachdenken müsstest.

Generell:
Ich bin jetzt nicht so sehr auf Deine PyQt-Problematik eingegangen, da ich glaube, dass die größeren Flaschenhälse woanders stecken (Sqlite ist hier mein Favorit). Diese Flaschenhälse solltest Du erstmal ausfindig machen (z.B. mit `time.time()` oder [mod]timeit[/mod] die Laufzeiten einzelner Programmteile bestimmen).

Vielleicht helfen Dir den Gedanken weiter und waren nicht völlig am Thema vorbei ;)

Grüße jerch
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

Hallo jerch, Danke für deine Antwort!
jerch hat geschrieben:Kannst Du bitte nochmal genauer beschreiben was Dein Programm machen soll? Willst Du zeitgleich die pcap-Daten vom Netzwerk nativ erhalten (sniffen) und in die DB schreiben/lesen? Ich bin aus Deiner Beschreibung leider nicht ganz schlau geworden.
Mein Programm soll ein Ethernet-Protokoll-Logger eines firmenintern verwendeten (auf UDP aufbauenden) Netzwerkprotokolls werden.
Dazu sollte permanent auf der Netzwerkschnittstelle den Datenverkehr mitgelesen, dann gefiltert, die interessanten Daten extrahiert und schlussendlich die Information in die Datenbank eingefügt werden. Gleichzeitig soll aber der Benutzer den ganzen (!) Datenstrom in einem Qt-Steuerelement (wie z.B. QTableView) anschauen, filtern sowie hin- und herscrollen können. Deshalb war mein erster Ansatz der von verschiedenen Pipes/Threads, da ja jede einzelne Stufe ihre Rechenzeit benötigt und ich auf keinen Fall die Oberflächendarstellung blockieren wollte. In Kombination mit dem GIL hat das aber anscheinend unberechenbare Folgen, denn genau das passiert nun.
jerch hat geschrieben:Ein Frage vorweg, nutzt oder brauchst Du die Relationen später, die Dir ein SQL-DBMS bietet? Wenn ja, brauchst Du eine skalierbare Lösung, die den Verwaltungsaufwand zeitnah erschlagen kann (Wie hoch ist das Datenaufkommen/Zeit? Kann Dein jetziges System das noch ohne Drops abarbeiten?). Sqlite ist da nicht die beste Wahl, da gerade Inserts für DBs>1GB extrem langsam werden. Bis hin zu einem Oracle/DB2-Cluster wäre hier alles denkbar.
Solltest Du die Relationen nicht brauchen (danach sieht Dein Code derzeit aus), ist eine performante "Datenhalde" das Mittel der Wahl. Beispiele hierfür wären key-value DBs. Diese sind bieten meist auch eine hohe Skalierbarkeit (bei vgl. geringeren Anforderungen gegenüber den relationalen DBMSen). Das HDF5 kenne ich leider nicht, in wie weit dies Deinen Anforderungen gerecht wird, beantwortet Dir sicherlich die Spezifikation.
Relationen brauche ich eigentlich nicht, es handelt sich nur um Datenfelder wie "Timestamp", "IP-Src", "IP-Dest" und "Data" (Größe variabel zwischen wenigen Byte und bis zu einem Megabyte, das könnte auch ein Problem sein, insofern nur statische Datenfeldgrößen möglich wären)
Über Key-Value-Datenbanken hab ich noch überhaupt nicht nachgedacht, welche Lösungen wären in diesem Feld empfehlenswert? Ich muss gestehen dass ich bis jetzt immer mit relationalen Datenbanken wie MySQL oder SQLite gearbeitet habe. SQLite hab ich nun ganz abgehackt da dies aus vielen verschiedenen Gründen Probleme bereitet.
CouchDB hab ich mir auch mal angesehen, das ist aber in diesem Fall auch die falsche Wahl, soweit ich das bis jetzt beurteilen konnte.
Eine schlanke, threadsichere und hochskalierbare Key-Value-Datenbank wäre ideal!
jerch hat geschrieben:Für mich hört sich Dein jetziger Ansatz so an, als wolltest Du viele Dinge parallel in Threads abarbeiten. Das geht in Python leider nicht, wie Du es vllt. von anderen Sprachen her kennst, da Python die Ausführung von Threads mittels des global interpreter lock (GIL) koordiniert und die Ausführung von Pythoncode auf einen aktiven Thread beschränkt. Braucht ein Aufruf innerhalb eines Threads zu lange, werden die anderen mit ausgebremst. Ausnahme sind hier viele low-level-Funktionen (z.B. time.sleep) die den GIL freigeben.
Die Problematik des GILs war mir zumindest ansatzweise bewusst, ich dachte aber erst, dass auch der Zugriff auf die libpcap den Gil freigibt, da es sich hierbei um eine IO-Operation handelt.. Dem ist aber leider nicht so, es wird ja nur die libpcap verwendet, was eine C-Funktion ist und solcherart C-Funktionen waren ja soweit ich weiß, der Grund warum der GIL überhaupt notwendig war.
jerch hat geschrieben:U.a. gibt auch der Großteil der PyQt-Bibliothek den GIL frei. (Als Tip: Alles was Qt nahe threaded passiert würde ich eher mit QThread umsetzen, hat den Vorteil, dass Du das Eventsystem nutzen kannst)
Brauchst Du allerdings viel Pythoncode in den Threads, bleibt das GIL-Problem bestehen.
Interessant, das heißt es wäre von Vorteil, so viel wie möglich mit PyQt-Funktionen zu realisieren, um möglichst wenig blockierende Phasen zu haben?
Den GIL gänzlich umgehen kann man ja mit QThread auch nicht, oder? Wo liegt im Detail der Vorteil wenn man statt einem Standard [mod]threading[/mod].Thread ein QThread Objekt verwendet?
jerch hat geschrieben:Evlt. hilft Dir dann das [mod]multiprocessing[/mod]-Modul weiter.
Das wäre eine echte Alternative, eigener Prozess heißt ja eigener GIL und somit echte Parallelität. Da wäre dann nur das Problem der Interprozesskommunikation zur Datenweitergabe, oder hältst du das unter Verwendung des [mod]subprocess[/mod]-Moduls für kein Problem?
jerch hat geschrieben:Falls das alles nicht hilft, wirds hässlicher, da Du dann evtl. Teile Deiner Applikation in c auslagern oder gar über einen Wechsel der Sprache nachdenken müsstest.

Generell:
Ich bin jetzt nicht so sehr auf Deine PyQt-Problematik eingegangen, da ich glaube, dass die größeren Flaschenhälse woanders stecken (Sqlite ist hier mein Favorit). Diese Flaschenhälse solltest Du erstmal ausfindig machen (z.B. mit `time.time()` oder [mod]timeit[/mod] die Laufzeiten einzelner Programmteile bestimmen).

Vielleicht helfen Dir den Gedanken weiter und waren nicht völlig am Thema vorbei ;)
Ja über einen Wechsel zu C habe ich auch gerade nachgedacht, ich vermisse dann allerdings die angenehmen Features von Python, sollte es nicht unbedingt notwendig sein, möchte ich schon bei Python bleiben.

Danke, deine Antwort hat mir schon sehr weitergeholfen. Ich werde mir nun den Multiprozess-Ansatz durch den Kopf gehen lassen und versuchen den jetzigen Flaschenhals zu finden, ich denke aber dass du mit deiner Vermutung, es liege an SQLite, Recht hast.
philistion
User
Beiträge: 108
Registriert: Sonntag 7. Februar 2010, 14:16

Ich hatte mit jerch eine Diskussion per PN gestartet, wir dachten uns aber nun, dass auch die anderen davon profitieren könnten. Ich poste deshalb den größten Teil des Texts:

...
philistion hat geschrieben:...
Wireshark ist uns bekannt, scheidet aber aus, weil die Möglichkeit Wireshark mittels Lua zu erweitern nur bedingt gute Ergebnisse für unsere Bedürfnisse liefert, wir hatten diesbezüglich schon eine Weile recherchiert, kamen dann aber zum Schluss dass die libpcap direkt zu verwenden hier besser geeignet sein müsste. Vor allem weil die speziellen Auswertungsaufgaben doch sehr aufwendig und komplex sind und diese nicht so einfach in Form eines Protokoll-Plugins in Wireshark integriert werden können.

Ich glaube ich habe mich in meinem Beitrag nicht ganz exakt ausgedrückt, insgesamt sollten natürlich recht große Datenmengen gespeichert werden, das sind Verbindungsdaten von mehreren Monaten, das heißt im Normalfall fällt pro Woche etwa 100GB an, das heißt etwa 150KB/s im Durchschnitt, wobei in der Nacht nahezu nichts anfällt, kann man sagen dass am Tag etwa 300KB/s durchgeht und an Nutzdaten aufgezeichnet wird. Das stellt nun keine allzugroßen Anforderungen an ein Backend, ansonsten stünden uns diverse High-Performance Raid 0 / Raid 1 Verschachtelungen zur Verfügung, die aber in diesem Fall nicht notwendig sind, wir haben hier lediglich ein Raid 5 Array mit insgesamt 2TB Speicher, da wir für 2 Monate mindestens aufzeichnen wollen.
Auch wenn sich der Durchsatz im Extremfall kurzzeitig sehr stark erhöht, denke ich nicht, dass wir da an die Grenzen eines normalen Desktop-Computers stoßen. Mehr als 1MB/s trat auch in unseren Stress-Tests nicht auf.

Es handelt sich bei der Anwendung um eine Überwachung eines "Schankanlagen-Protokolls", das heißt es geht darum, im Nachhinein bei der Monatsabrechnung möglichst genau sagen zu können, ob an einem bestimmten Zeitpunkt z.B. ein Getränk gezapft wurde oder nicht.

Das Problem ist also nicht, möglichst viele Daten in kurzer Zeit durchzubringen, sondern über einen langen Zeitraum viele Daten abzulegen und durchgehend darauf einen performanten Zugriff zu ermöglichen. Pro Sekunde geht da nicht viel Traffic rüber, aber durch die teilweise monatelang geplante Aufzeichnung, sammelt sich ein doch sehr großer Datenhaufen an und der soll immer möglichst schnell gefiltert und durchsucht werden können.

Ich habe das GIL-Problem etwa vor einer Woche umgangen, indem ich wie nun auch du geschrieben hast, das multiprocessing-Modul verwendete, das eigentliche Problem ist nun verschwunden, wir haben bis jetzt keine Probleme, es läuft flüssig mit einer SQLite Datenbank und verschiedenen Prozessen, einem der die libpcap bedient und die gesnifften Pakete an einen Decoder-Prozess übergibt, dieser überprüft dann die CRC und fügt das Paket bei Erfolg in die Datenbank ein.

Der jetzige Knackpunkt ist eigentlich nur noch die Frage, ob SQLite bei den riesigen Datenmengen noch in halbwegs passabler Bedienzeit die Filter-Queries ausführt.

Meine Programmiererfahrungen liegen vor allem im C und C++ Bereich, habe dort sehr viel Mikrocontrollerprogrammierung (ARM) aber auch Desktop-Anwendungen unter Windows und Linux gemacht, Python nun seit ein paar Jahren, Lisp, Prolog, Pascal, Scheme, Haskell und ein bisschen Ruby hab ich auf der Uni gelernt.
Ich bin aber nun überzeugt, dass ich mit Python auskomme, abgesehen davon möchte ich nicht auf die vielen angenehmen Features verzichten, die angenehmen Testing-Frameworks (wir verwenden nose) sind da nur ein Teil.

Nehmen wir mal an, wir bekommen ab einer bestimmten Datenmenge große Performanceprobleme beim Filtern, es dauert einfach zu lange.
Fällt dir eine Alternative zu SQLite ein, die Open-Source und von Python aus verwendet werden kann?
Ich denke im Moment wegen der hohen Kardinalität der Datenspalten an eine B+Tree Datenbank wie z.B. tokyocabinet: http://packages.python.org/tokyocabinet ... index.html

Da tokyocabinet vielversprechend aussieht, werden wir glaube ich dieses einmal ausprobieren. Alternativvorschläge sind aber sehr gern gesehen, wäre fein wenn dir noch was einfällt. Oft übersieht man ja die naheliegendsten Dinge..
jerch hat geschrieben:Zum UDP:
Habe ich Dich da richtig verstanden, die Schankanlagen senden bei Zapfung eine Art Commit-Paket über die erfolgte Zapfung? Warum macht Ihr sowas mit UDP? Solange Ihr das nur intranetweit betreibt und sicherstellen könnt, dass der Protokollierungsrechner immer verfügbar ist, mag das gehen. Sobald aber Kunden oder das Internet ins Spiel kommen sind mit UDP packet drops vorprogrammiert und eine verlässliche Messung ist dann nicht mehr möglich. Aber ich will mir hier nicht Deinen Kopf zerbrechen Wink

Zum Datenaufkommen:
In der Tat sind 300KB/s nicht viel, damit werden meine ganzen Hochverfügbarkeitsüberlegungen hinfällig. Ihr müsstest halt darauf achten, dass nicht eine andere UDP-Quelle by accident den Protokollrechner plötzlich mit unrelevanten UDP-Paketen beschäftigt und so Python ins Schwitzen bringt. In einem Intranet ist das natürlich kein Problem, ansonsten könnt Ihr die Pakete ja Vorfiltern lassen.

Storage/Backendsystem:
Mit 2TB an Nutzdaten über 2 Monate seid Ihr am Limit von SQLITE angekommen, da es mit der default page size von 1024 bytes bis 2^41 addressieren kann. Den Wert kann man allerdings verändern, wobei noch grössere Dateien auch vom Dateisystem unterstützt werden müssen.
Wie ich dich jetzt verstanden habe, ist Nebenläufigkeit des Backends für Euch kein wichtiges Kriterium (max. ein schreibender und ein lesender Zugriff). Daher ist SQLITE durchaus geeignet --> http://www.sqlite.org/whentouse.html
Es erreicht eine passable Lesezeit auch für eine Recordanzahl jenseits der 1M, nur die Inserts machen dann Probleme (finde den Benchmark gerade nicht mehr). Der Umstieg auf ein grösseres RDBMS lohnt bei Euren Anforderungen nicht, da diese für Einzelzugriffe allesamt schlechter sind (alter Benchmark hier: http://www.sqlite.org/speed.html). Die Grossen spielen ihre Vorteile erst mit höherer Nebenläufigkeit aus, da SQLITE die komplette DB-Datei lockt.
Key-value storages gibt es eine ganze Menge. Die Hysterie um cloud computing etc. hat hier einiges an Systemen mit sehr unterschiedlichen Lösungsansätzen zutage gefördert. Dementsprechend verschieden sind auch deren APIs, von einfachen get(key) und set(key, value) bis hin zu einem Subset von SQL-Befehlen ist da alles zu finden.
Hier mal eine kleine Liste: http://www.metabrew.com/article/anti-rd ... ue-stores/
Tokyo Cabinet ist eine sehr gute Wahl, sie gilt auch unter den key-value Systemen als sehr performant und bringt verschiedene DBs mit (die fixed length DB ist sogar noch schneller als der BTree). Sie ist auf jeden Fall einen Blick wert. Du muss halt schauen, ob die gebotene Funktionalität Deinen Ansprüchen gerecht wird. Gerade das Umdenken und Portieren vom relationalen Modell hin zur simplen key/value-Abstraktion birgt gewisse Fallstricke. Solltest Du in der Anwendung zu viele Relationen brauchen, lohnt der Umstieg nicht, da Du sonst die Hälfte der RDBMS-Goodies nachbilden musst (joins, Prüfen der Datenintegrität etc.). Generell kann man sagen, dass je komplexer die Daten strukturiert sind, der Einsatz eines key/value-Systems unsinniger wird, da die Komplexität die Anfragen in die Höhe treibt während ein RDBMS eine Anfrage braucht und die Magie mit hochoptimierten Code im DBMS selbst passiert.
Im konkreten Fall würde ich schauen, ob Du Deine Daten mit der Tokyo Cabinet-API ohne grosse Verrenkungen abstrahieren kannst (read-optimiert, da das Schreiben offensichtlich nicht so kritisch ist). Im Zweifelsfalle würde ich das dann gegen SQLITE benchmarken.
Noch eine Sache zu RDBMS, verzichte lieber auf den Einsatz eines ORM, da dies unnötigen Overhead erzeugt.

Programmiererfahrungen:
Sorry, dass ich das nachgefragt habe, ich hatte schon Anfragen von Leuten, die eine komplexere Sache angehen wollten und es sich herausgestellt hat, dass sie über keine hinreichenden Programmierkenntnisse verfügten.
Eine Frage hab ich trotzdem hierzu, warum realisierst Du das Ganze nicht in C++ und Qt bei Deinen Vorkenntnissen in C/C++?
Wahrscheinlich kenne ich die Antwort selbst nur zu gut. Ich komme ebenfalls aus der C/C++-Ecke, vorwiegend Anwendungsprogrammierung, auch mit Qt, das Prototyping hat mich dann zu Python gebracht. Python ist schon eine tolle Sache, während man in C++ noch über dem selbst zu implementierende Datenmodell hängt, hat man in Python schon die halbe Anwendung fertig.
Die Wahl von UDP ist großteils historisch bedingt, wir tendierten damals nach einigen Benchmarks zu diesem Protokoll, da wir in den meisten Fälle die "Sicherheit" von TCP nicht brauchen, wo wir sie brauchen, kontrollieren wir manuell mit CRC und senden ein Antwortpaket (OK).
Wechseln ist schwierig, da das ein Standard ist, der an vielen Orten verwendet wird, ein Wechsel lässt sich hier schwer durchsetzen, wenn nicht ein konkretes Problem auftritt, das durch die Verwendung von UDP bedingt ist.

Danke für die Liste, ich habe eben gesehen, dass es auch eine tokyocabinet Table Datenbank gibt, also eine sogenannte Column-Based-Database, das wäre für meine Daten (hohe Kardinalität) ideal!

Mit B-Bäumen habe ich noch nie gearbeitet, glaubst du das macht in diesem Fall Sinn?
Ich gehe mal davon aus, dass die tokyocabinet Table Datenbank stark für diese Zwecke optimiert wurde und deshalb hier eine gute Wahl wäre.

Eben wegen dem Problem bei den großen Datenmengen (SQLite speichert ja alles in eine Datei, das ist bezüglich der Datensicherheit auch nicht ideal.. Tokyocabinet scheint hier besser abgesichert zu sein)

Bei SQLite war halt noch der Vorteil, dass man auf die fertigen Models wie z.B. QSqlQueryModel zurückgreifen kann, für Tokyocabinet muss ich mir hier wohl selbst eines von QAbstractItemModel ableiten.
Wäre es nicht für viele Leute interessant, eine Art QTokyoCabinetModel verwenden zu können?
Wenn jemand Interesse hat, bitte melden, vielleicht können wir ja gemeinsam eine allgemeine Lösung auf die Beine stellen und auf GitHub o.ä. verfügbar machen?


Warum ich nicht in C programmiere? Nun ja, abgesehen von den vielen Erleichterungen beim Entwickeln (-> große Zeitersparnis) soll die Software sowohl unter Linux als auch unter Windows laufen. Das wäre unter C zwar auch möglich, aber wohl mit mehr Aufwand verbunden. Außerdem sind viele Teilaufgaben des Projekts unter Python wesentlich schneller zu realisieren, da eben auf sehr viele Bibliotheken und Hilfsmittel zurückgegriffen werden kann, wo hingegen in C doch nahezu alles "per Hand" gemacht werden muss.

mfG
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

UDP:
Ihr habt sicher aus guten Gründen das damals so entschieden und solange es für Euch funktioniert, ist es ja auch in Ordnung so. Die CRC-Sache mutet halt ein wenig wie Verbindungsorientiertheit auf Applikationsebene an, während TCP das auf Transportebene schon erledigen könnte. Auch wirkt Dein Programmiervorhaben so, als müsstest Ihr hier eine weitere Sicherheit einbauen, wo ein kleiner TCP-Handshake mit "hallo, hab grad 2l gezapft" es hätte sauber protokollieren können. Aber egal...

B-Baum:
Ja B-Bäume sind hierfür gut geeignet. Eine Abfrage liegt bei log(n), für stark verzweigte Bäume hat der Logarithmus kaum noch einen Einfluss. Tokyocabinet nutzt B+Bäume, die haben noch ein paar spezifische Optimierungen für Bereichssuche etc.
Wie es um die table/column based DB in Tokyocabinet steht, weiß ich nicht.

QTokyoCabinetModel:
Willst Du das nativ in C++ schreiben und per SIP an Python binden (analog zu PyQt)?
Ich bin mir nicht sicher, ob sich ein solches Model sinnvoll verallgemeinern lässt, da Du mit key/value-DBs ziemlich viel "zu Fuß" erledigen musst und mit veränderter Datenbasis ein erneutes stärkeres Handanlegen ans Model unvermeidbar ist.
Antworten