C++ Konzept persitente Daten

T_55

Lieutenant
Registriert
Feb. 2013
Beiträge
638
Hallo,

ich möchte in der nächsten Zeit mal meine Codes zum Speichern und Abrufen von persistenten Daten überarbeiten. Aktuell speichere ich in CSVs Datenpunkte(Klimadaten) in ca 3 bis 6 Spalten getrennt durch Semikolon. Jede Zeile ist ein Datenpunkt. Die maximale Größe der CSVs gehen so bis max 10GB. Der normale Vorgang ist die Daten in den RAM zu laden und dann dort solange wie benötigt zu halten da mehrere Workerthreads parallel und wiederholend diese Daten nutzen.

Zwei Dinge möchte ich verbessern:
  • Die Datenmengen auf Platte reduzieren.
  • Das Einlesen der Daten von Platte auf RAM beschleunigen.

Thema: Spalten vs binär
Das Einlese-Ziel ist im RAM immer ein vector mit ensprechendem Struct in dem ausschließlich simple Datentypen wie float/int vorkommen. Meistens 12Bytes Struct. Aktuell wird beim Lesen der String aus jeder Zeile zerlegt und dieses Stringfragment zu int/float gewandelt. Das ist natürlich umständlich. Da die Datentypen primitiv sind könnte man sicher ohne Risiko das komplette Struct binär abspeichern. Das wäre mein erstes Ziel. Ich habe mal irgendwo gelesen, dass man generell beim Files einlesen größere Stücke einlesen sollte und nicht nur Zeile für Zeile um die Geschwindigkeit zu erhöhen. Idee daher ein Array für das Struct zu erstellen mit fixer size. Man spart dann auch etliche Zeilenumbrüche die auch Zeichen sind und Platz auf der Platte kosten.
Mein Ansatz wäre jetzt:
  • Das Struct zur Sicherheit mal mit #pragma pack(push,1) für ein immer exaktes Fitting.
  • Das Struct als Array-Block mit zb 10000 Einträgen wird dann binär als eine Zeile abgelegt, so als Ansatz. myfile.write((char *) &StructArray, sizeof(StructArray));
  • Einlesen dann per fcntl / unistd soll sehr schnell sein: https://stackoverflow.com/questions/17925051/fast-textfile-reading-in-c

Thema: Komprimierung
Mir ist aufgefallen, dass die Daten scheinbar gut zum Packen geeignet sind. Eine typische 5.5 GB Datei ist per 7z gepackt 0.318 GB !
Es drängt sich mir daher der Gedanke auf ob der Zeitverlust einer Decompression durch die so geringe einzulesende Datenmenge vielleicht sogar egalisiert wird? Die Anforderung an die CPU steigt zwar aber es muss dafür ja auch viel weniger von Platte gelesen werden. Evt ist die Decompression auch multicore skalierbar möglich dann würde das noch weniger ins Gewicht fallen.
Eine geringe Datenmenge bringt langfristig auch eher eine SSD ins Spiel wo sich aktuell nur eine Datengrab-HDD lohnt. SSD wäre wiederum ein Pluspunkt beim Thema Einlesespeed.

Aspekte:
  • Compression Ratio: je höher desto besser aus Speicherplatzsicht.
  • Compression Speed: das ist völlig egal. kann und darf langsam sein.
  • Decompression Speed: damit die Daten dann schnell in den RAM kommen sollte das natürlich nicht zu lahm sein. Je höher die Compression Ratio desto geringer der Decompression Speed.
  • Zugriff: Im Hinterkopf hab ich beim Ganzen noch, dass ich bei meinen Zeitstempelbasierten Daten auch einen bestimmten Startzeitpunkt finden muss von dem ab dann die Daten benötigt werden. Aktuell springe ich per seekg() im Abstand von 2000000 Zeichen weiter bis ich den Zeitpunkt gefunden habe. Das geht gut und sehr schnell. Wenn allerdings alles komprimiert ist, wäre meine Frage wie das Finden von einem Zeitpunkt dann geht...
  • Hinzufügen: Wäre es gut wenn sich bestehende Daten anhängen lassen um bestehende Datensätze um aktuelle Daten zu erweitern.

Im Netz sind mir auf Anhieb zwei Algos ins Auge gesprungen:
LZ4 scheint für Speed ausgelegt zu sein während brotli eher bessere Kompression hat aber auch noch ganz ok ist von dem Speed.
Ansonsten klang das noch interessant:
  • FSST: https://github.com/cwida/fsst Mit der Behauptung im Vergleich zu LZ4: "similar decompression speed and compression speed, and better compression ratio."
Will aber auch keine Wissenschaft daraus machen!, soll einfach eine gute pragmatische Verbesserung werden, gerne mit einer Lib die einfach zu nutzen und zu installieren ist (header only ist mir zB immer sympathisch).

Hier gibts ein Vergleich vieler Algos mit verschiedenen Settings:
https://quixdb.github.io/squash-benchmark/#results

Meine Fragen wären:
  • binär speichern lohnt sich, richtig?
  • lohnt sich die Sache mit dem Binär-Array im Gegensatz zu Binär-Zeile-für-Zeile und wenn ja, wie groß sollte das Array sein? Bei 12Bytes Struct: ArrSize=10000 wären 0.12 MB, 100000 wären 1.2 MB. Gibt es da eine bestimmte Größe die gut ist?
  • Welche Lib/Algo würdet ihr empfehlen?
  • Kompensiert die geringere Datenmenge von komprimierten Daten die eingelesen werden müssen die Decompression Zeit? Weniger Daten von Platte holen -> spart Zeit, Daten entpacken -> kostet Zeit. Was fällt stärker ins Gewicht?
  • Kann man in komprimierten Daten einen Abstand/Block x solange springen + kurz extrahieren bis gewünschter Zeitstempelbereich gefunden? Also wie oben beschrieben das "schnelle finden" durch größere Spünge in den Daten, geht das auch bei komprimierten Daten?
  • Es gibt ja dann eine Kaskade aus Buffern und Blöcken bis die Daten im Vector landen. So stelle ich mir das vor:
    • 1: Buffer beim Auslesen: im stackoverflow-beispiel ist zB BUFFER_SIZE = 16*1024
    • 2: Buffer bei Decompression. Das Buffer-Thema verstehe ich da noch nicht gut. Da es komprimiert ist, weiß man ja nicht wieviel ungepacktes im gepackten genau steckt...?
    • 3. Block BinärStructArray -> muss in vector.
    • Ich schätze die Buffer und Wahl der BinärStructArray-Size sollte/muss man möglichst schlau aufeinander abstimmen richtig?
Ziel ist eine ausgewogene Sache aus guter Compression Ratio mit gutem Decompression Speed. Ich kann nicht einschätzen wie stark sich die genannten Ausgestaltungen von Binär, Array, Buffer, Lib/Algo so auswirken vielleicht habt ihr da bisschen Input auf die Fragen denn Komprimierung in Abstimmung mit ausreichendem Speed ist vermutlich in vielen Bereichen eine lang genutzte Standardanwendung.

Soweit erstmal ;)
Grüße
 
Zuletzt bearbeitet:
Ich hab mir jetzt nicht alles durchgelesen, aber wie waere es einfach mit einer Datenbank?

Eine Standard Datenbank, egal ob relational oder NoSQL ist mit Docker in 2 Minuten aufgesetzt und loesst sehr viele deiner Probleme automatisch. So kannst du z.B. schneller auf einzelne Daten zugreiffen und musst nicht immer ein ganzes File lesen, etc.

Auf die Idee, irgendwelche Daten in CSV zu lagern waere ich gar nicht gekommen. :D
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Sonnenkarma, up.whatever, Burfi und 2 andere
Ich würde hier auch einfach auf ne etablierte Datenbank setzen. Mit SQLite geht das ganze auch ohne externe Dependencies, wo du extra nen DB-Server aufsetzen müsstest.

Binär abspeichern wäre zwar ganz nett und kompakt, Kompression wäre das I-Tüpfelchen, allerdings musst du dann immer das Programm als Zugriffsschicht dazwischen schalten. Mit ner DB könntest du mit x beliebigen Tools drauf zugreifen, bspw. auch via Excel und ODBC und nette Statistiken erstellen, falls irgendwann gewünscht.

Eine Kompression der Datenbank könntest du dann anderweitig extern, imho zuverlässiger, erledigen. In Windows wäre das transparent via NTFS möglich.

Ggf. sowas ausprobieren: https://github.com/ryanhomer/sqlite3-compression-encryption-vfs
 
  • Gefällt mir
Reaktionen: Sonnenkarma, Hayda Ministral und Nase
Ich hatte früher mal die Sachen mit SQLite versucht und bin dann bewusst auf CSV umgestiegen weil es viel unkomplizierter war. Als Nicht-Berufs-Coder beherrsche ich diese Datenbanksprachen auch nicht wirklich. SQLite war zumindest für mich damals ein uneffektiver Krampf.
Ich benötige auch den ganzen Kram eigentich nicht den die Datenbanken können. Das ganze läuft lokal ab daher auch kein Netzwerkzugriff etc nötig.
Werde aber natürlich mal drüber nachdenken bin inzwischen etwas fähiger als damals aber dennoch glaube das sprengt meinen zeitlichen Rahmen wenn ich jetzt nochmal in die Datenbank(sprachen) Welt eintauche (mit genannten Anforderungen...)
 
Yuuri schrieb:
Binär abspeichern wäre zwar ganz nett und kompakt, Kompression wäre das I-Tüpfelchen, allerdings musst du dann immer das Programm als Zugriffsschicht dazwischen schalten
Nicht zu vergessen, dass man sich dann auch noch im Indizes, Querys, Aggegationen und so selbst kümmern müsste. Sowas bringt auch jede Datenbank automatisch mit.

T_55 schrieb:
Werde aber natürlich mal drüber nachdenken bin inzwischen etwas fähiger als damals aber dennoch glaube das sprengt meinen zeitlichen Rahmen wenn ich jetzt nochmal in die Datenbank(sprachen) Welt eintauche (mit genannten Anforderungen...)
Aber der ganzen Code, die Tests, das Tooling außenrum, etc. kostet dich keine Zeit? :D Das würde ich mir noch mal genau überlegen.

Du könntest ja mal einen kleinen Beispieldatensatz bereitstellen und welche Operationen darauf hauptsächlich ausgeführt werden. Dann lässt sich das wahrscheinlich deutlich besser beurteilen.

Bisher habe ich nur das gelesen:
T_55 schrieb:
Zugriff: Im Hinterkopf hab ich beim Ganzen noch, dass ich bei meinen Zeitstempelbasierten Daten auch einen bestimmten Startzeitpunkt finden muss von dem ab dann die Daten benötigt werden. Aktuell springe ich per seekg() im Abstand von 2000000 Zeichen weiter bis ich den Zeitpunkt gefunden habe. Das geht gut und sehr schnell. Wenn allerdings alles komprimiert ist, wäre meine Frage wie das Finden von einem Zeitpunkt dann geht...
Das wäre mit 'ner Datenbank ein Kinderspiel. Dafür muss man der Datenbank nur sagen "gib mir X Elemente ab Zeitstempel Y". Fertig. Kompression, Dekompression, Treffer finden, sortieren, etc. alles voll automatisch und transparent.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Sonnenkarma, Raijin und Nase
T_55 schrieb:
Als Nicht-Berufs-Coder beherrsche ich diese Datenbanksprachen auch nicht wirklich.
SQL, vor allem SQLite ist nicht wirklich schwer, höchstens ungewohnt, wenn man andere Dialekte gewohnt ist (MySQL, Postgres, SQL Server, Oracle, ...). Da guckst du dir kurz nen Tag ein paar Tutorials an und kennst dich dann ausreichend gut aus. Mit SQLite hast du nicht ganz die Power einer großen SQL-Engine, allerdings ist es eben für jetzt deinen Fall gedacht - schlanke Dependency, keinen App-Server, keine anderweitigen Abhängigkeiten.

Prinzipiell erstellst du die DB mit CREATE DATABASE, mit CREATE TABLE erstellt du Tabellen, mit INSERT INTO fügst du Daten hinzu und mit SELECT rufst du Daten ab. Viel mehr brauchst du da nicht. Es ist auf jeden Fall bedeutend einfacher die Daten via SQL zu filtern, als den Firlefanz in Programmcode nachzubilden.

Anfangs kannst du das auch alles via GUI zusammenklicken. Mal ne Übersicht zu ein paar Tools - HeidiSQL, Adminer, DataGrip wären hier meine Favoriten. Ganz simpel wäre DB Browser for SQLite oder Database.NET, Toad war damals auch ganz gut, scheint wohl aber nich mehr kostenlos zu sein.

Die ausgeführten Queries werden dir dabei auch immer angezeigt, welche du direkt für nen Schnellstart übernehmen könntest.
SQL:
SELECT *
FROM daten
ORDER BY id DESC
LIMIT 30
Damit holst du die letzten 30 Einträge. Wie viel Programmcode musst du stricken, dass du das aus deinen Datensätzen rausfilterst?
SQL:
SELECT *
FROM daten
WHERE datum >= date(NOW(), '-1 week')
ORDER BY id DESC
Für alle Datensätze innerhalb einer Woche. Wieviel Logik musst du dafür bauen? Das alles bringt die SQL-Engine bereits mit. Auch Aggregationen sind kein Problem und werden bereits mitgeliefert. Bspw. die Durchschnittswerte aller Daten pro Tag für die letzten x Wochen/Monate/... Oder was du dir mit den Queries halt zusammenbaust.
SQL:
SELECT *
FROM daten
WHERE datum BETWEEN '2020-10-01 00:00:00' AND '2020-10-31 23:59:59'
ORDER BY id DESC
Für die Datensätze aus Oktober 2020.

Deine CSVs, falls gewünscht, kannst du dann auch ganz einfach exportieren.
Code:
>sqlite3 c:/sqlite/chinook.db
sqlite> .headers on
sqlite> .mode csv
sqlite> .output data.csv
sqlite> SELECT customerid,
   ...>        firstname,
   ...>        lastname,
   ...>        company
   ...>   FROM customers;
sqlite> .quit
 
  • Gefällt mir
Reaktionen: Sonnenkarma, PcFliege, NJay und eine weitere Person
Im Grunde brauche ich jetzt nur eine Zwischenschicht einfügen mit dem (De)Kompressionsalgo und die Vorgänge auf binär-read-write umschreiben. Meine Fragen gingen ja schon in gewisser Weise ins Detail dazu. Ich war jetzt kurz davor mich einfach zwischen LZ4 oder brotli zu entschieden und wollte eben nochmal fragen ;)
Datenbanken sind natürlich professionell und bieten auch Möglichkeiten die man vielleicht irgendwann auch mal nutzen kann aber aktuell für den Zweck ist eine Datenbank für im Schnitt 3 float Spalten nicht völlig übertrieben? Es soll ja auch eine Verbesserung zum aktuellen Stand bringen, am Ende ist es langsamer oder nur gleich schnell wie jetzt und kommt an ein LZ4 oder brotli gar nicht ohne Weiters ran vom DeKompressions/Speed Verhältnis. Also ich denke natürlich schon das Datebanken dazu in der Lage sein können wenn man sie dazu bringt aber das dies so einfach ist (für mich) glaube ich nicht.

Bei Datenbank muss ich mich eben um viel mehr kümmern
-Datenbank
-Datenbanksprache
-(De)Kompression
-Binär

Beim meinem aktuellen Vorhaben nur
-(De)Kompression
-Binär
 
T_55 schrieb:
Bei Datenbank muss ich mich eben um viel mehr kümmern
-Datenbank
-Datenbanksprache
-Kompression
-Binär
Datenbanken speichern in dem Format, das du ihnen mitgibst. Wenn du sagst, dass du eine Zahl speichern willst, dann speichert das Teil eine Zahl und keinen String. Die Daten sind also automatisch schon "binär".

Kompression hängt jeweils von der Datenbank und bzw. Storage Engine ab. In MySQL/MariaDB InnoDB genügt da im einfachsten Fall schon ein ALTER TABLE my_table ROW_FORMAT=COMPRESSED;. Und schon wird alles transparent (de)komprimiert was mit der Tabelle zu tun hat.
In MongoDB wird seit Jahren standardmäßig die WiredTiger Engine mit snappy Kompression genutzt, ohne dass man noch irgendwas einstellen muss (ist aber keine SQL Datenbank).
Wie das in sqlite aussieht, weiß ich nicht. Noch nie benutzt.

Die Datenbank selbst sollte nun auch kein Problem sein. Das ist im Endeffekt auch einfach nur ein Programm, das installiert wird und dann läuft's.

Nur die Sprache ist tatsächlich mit Aufwand verbunden. Alles andere kann man vernachlässigen.

Aber die Entscheidung musst du natürlich selbst treffen. Du könntest so einen kleinen SQL Kurs auch als Investition in die Zukunft betrachten.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Sonnenkarma
Von MongoDB hab ich schon viel Gutes gehört, stand damals auch auf einer Liste von mir bevor ich mir dann mit SQLite das DB Trauma eingefangen habe ;) Snappy ist wohl auf Speed ausgelegt eher weniger auf Kompression. Also in meinem Link ist die Ratio nicht besonders gut im Vergleich zu den anderen.
Will mich auf keinen Fall gegen Datenbanken wehren, es reizt mich (wie damals auch schon) natürlich da vielleicht nochmal zu gucken aber aktuell ist die Sprache echt so wie Assembler für mich und man hat weniger Möglichkeiten der Feinjustierung. So Sachen wie "Advise the Kernel of acces pattern" (posix_fadvise) wie der Typ auf Stackoverflow zb nutzt um noch bisschen was rauszuholen sind mit DB eher schwer (nur als Beispiel).
Hab auch das Gefühl die Standard-Implementierungen der DB sind nicht so auf Kompression sondern eher auf Speed ausgelegt. Ich hab aktuell einen guten funktionierenden Zustand und will ja nur was ändern, wenn sich mit angemessenen Aufwand, auch etwas merklich verbessert. Vor allem beim Speicherplatz sparen sehe ich viel Potential und da glaube ich wird es schwer ein LZ4 oder brotli zu schlagen. Und wenn ich auf zb 15% runter kann dann will ich bei gleichem Speed ungern den selben Aufwand (oder mehr) betreiben um dann bei einer DB nur auf zb 35% zu kommen.
 
Zuletzt bearbeitet:
Ich stelle mir hier die ganze Zeit die Frage ... Du reitest drauf rum, dass eine Datenbank für Deine Anwendung viel zu übertrieben und komplex wäre, machst Dir aber gleichzeitig tiefe Gedanken über Komprimierung, Indizes, Zugriff auf und von in binärform selbst verwalteten Daten.

Das hakt doch ... Du sparst garantiert Zeit und "Hirnschmalz", da für Dein Vorhaben eine DB doch prädestiniert ist - haben hier schon andere ausführlich beschrieben. Es bringt eben vieles schon mit, wozu herrje das Rad neu erfinden?

Klingt für mich fast so, als wolltest Du zwanghaft den schwierigeren Wegen einschlagen, no offense :D
 
  • Gefällt mir
Reaktionen: JP-M, maloz, up.whatever und 3 andere
Mit Kompression hast eben das Problem dass du die Daten immer komplett lesen musst weil du nicht weißt an welchem offset du den Teil findest der dich interessiert.

Was du machst klingt sehr sehr nach time series database
Influxdb ist eine der bekanntesten.

https://docs.influxdata.com/influxdb/v2.0/write-data/
 
  • Gefällt mir
Reaktionen: T_55, maxpayne80 und KitKat::new()
Wäre eine Zeitreihendatenbank hier nicht besser geeignet?
Das würde genau das bieten was er braucht und wohl besser dafür optimiert sein als Standard SQL.
Ergänzung ()

cloudman schrieb:
Was du machst klingt sehr sehr nach time series database
Influxdb ist eine der bekanntesten.

https://docs.influxdata.com/influxdb/v2.0/write-data/
Ach hier ista ja schon dabei 👍
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: BeBur
Deine Recherche zu den Komprimierungsalgorithmen war wohl nicht besonders ausführlich: https://github.com/facebook/zstd
Zstd dekomprimiert bei höheren Ratios sogar schneller.

Zugriff zu bestimmten Daten mit Komprimierung: Du musst immer einzelne Blocks komprimieren, z.B. 50000 Datenreihen. Die einzelnen Blocks kannst du einfach aneinanderhängen. Dann brauchst du noch ein Index, ob extra Datei, am Anfang der selben Datei als Header oder immer vor einem Block mit Offset zum nächsten ist dir überlassen. Im Index steht dann drin: "Block mit Datenreihen 100001-150000 ist bei Byte 123 zu finden und 987 Bytes groß". Dann den Block von Anfang an bis zu den gewünschten Daten dekomprimieren.


Ja. Binär lohnt sich, nicht nur aus Speicherplatz- sondern auch aus Performance-Sicht. Weniger Bytes die durch die CPU gehen, kein Interpretieren der Bytes, sondern kann einfach 1:1 so im RAM abgelegt werden und direkt drauf zugegriffen werden.

Ja, in Chunks statt einzelne Datenreihen zu lesen bringt enorme Performanceboosts. Nicht nur der Datenträger wird viel effizienter ausgelastet, auch bekommst du hier u.U. Vorteile durch CPU-Caches und so Dinge wie Branch Prediction, wenn die CPU nicht immer zwischen verschiedenen Aufgaben und Daten hin und her springen muss. Aber das sind Mikrooptimierungen, um die du dir noch keine Sorgen machen solltest. Der Hauptvorteil wird das erste sein, dass du die Latenz (I/O-call etc. bis Daten da sind) jeweils nur einmal pro Chunk statt pro Datenreihe hast. Stell dir vor du musst deine Badewanne füllen und musst dazu Wasser aus der Küche holen. Einmal hast du eine 1L Flasche und einmal einen 10L Eimer. In beide Dinge bekommst du 1L gleich schnell rein (Datendurchsatz), aber bei der Flasche musst du 10 mal so häufig hin und her laufen (Latenz).
Welche Chunkgrößen gut sind testet du am besten einfach aus. Einmal mit 100, dann mit 1024, dann 10240. Solange es schneller wird, weiter vergrößern. Jede Chunkgröße wird deutlich schneller sein als deine jetzige Lösung mit Zeile für Zeile.

So Sachen wie "Advise the Kernel of acces pattern" (posix_fadvise) wie der Typ auf Stackoverflow zb nutzt um noch bisschen was rauszuholen sind mit DB eher schwer (nur als Beispiel).
Darüber musst du dir bei Datenbanken eben keine Gedanken machen, da die Datenbank das für dich macht. Außerdem sind das Mikrooptimierungen, um die du dir noch keine Gedanken machen solltest, du wirst da noch viel wichtigere Baustellen haben, die sehr, sehr viel mehr + bringen als sowas - wie das oben.


Wenn du das alles selbst machen willst um so low-level Kram zu lernen, nur zu. Ansonsten kann ich mich den anderen nur anschließen. Erfinde das Rad nicht neu, nimm etwas, das es schon gibt und genau dafür gemacht ist und das auch noch besser macht, als du es irgendwie könntest. Ich Verspreche dir, du wirst damit dein Ziel schneller erreichen und das wahrscheinlich sogar noch besser.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: up.whatever, T_55 und BeBur
T_55 schrieb:
Ich hatte früher mal die Sachen mit SQLite versucht und bin dann bewusst auf CSV umgestiegen weil es viel unkomplizierter war. Als Nicht-Berufs-Coder beherrsche ich diese Datenbanksprachen auch nicht wirklich. SQLite war zumindest für mich damals ein uneffektiver Krampf.
Sorry, aber SQLite soll ein "uneffektiver Krampf" sein und stattdessen arbeitest du mit 10 GB großen CSV-Dateien, die alle Daten in Strings speichern? What? Der einzige Krampf ist der, den du dir selbst baust indem du das Rad neu erfindest. Datenbanken sind genau für diesen Zweck geschaffen, weil sie nicht nur für die Datenspeicherung zuständig sind und dies äußerst effektiv tun, sondern weil sie gleichzeitig Zugriffs- und Suchmechanismen bieten, die du bei einer CSV gar nicht hast. Bei einer CSV in der Größenordnung von 10 MB mag das ja noch ok sein, aber 10 GB sind Wahnsinn, um nicht einen anderen Sinn zu nennen, der mit S anfängt ;)

T_55 schrieb:
Ich benötige auch den ganzen Kram eigentich nicht den die Datenbanken können.
Na eben doch. Du willst alles mögliche nachbauen was eine Datenbank bereits fertig mitbringt.

Mach doch einfach mal einen Test: Installiere SQLite und bau dir mit ein paar Klicks deine 6-spaltige CSV-Tabelle nach, auf die korrekten Datentypen achten. Anschließend importierst du die CSV in SQLite und guckst dir mal an wie groß die Datenbank hinterher ist.

T_55 schrieb:
Als Nicht-Berufs-Coder beherrsche ich diese Datenbanksprachen auch nicht wirklich.
Das wiederum ist dein persönliches Problem und nicht der Datenbank anzulasten. Nu ist SQL allerdings auch kein Hexenwerk und wenn du wie du sagst "den ganzen Kram" eigentlich nicht brauchst, werden deine SQL-Statements auf banale SELECT, INSERT, UPDATE und DELETE hinauslaufen. Also auch keine Foreign Keys, JOINs und dergleichen. Ergo hält sich auch die Einarbeitung in SQL arg in Grenzen und wird mit tödlicher Sicherheit schneller und einfacher ablaufen als wenn du das Rad nun mehrfach neu erfindest, indem du Komprimierung- und Zugriffsfunktionen händisch schreibst und optimierst. Denn wenn du das aus dem Ärmel schütteln könntest, würdest du ja hier auch nicht fragen. Es ist daher deutlich sinnvoller, deine Zeit und Energie in die Einarbeitung in SQL zu investieren, weil du es spätestens beim nächsten Projekt dann "richtig" machen kannst, ggfs dann sogar mit einer Netzwerkanwendung und einem SQL-Server. Das was du dir bei deiner CSV-Lösung erarbeitest, ist zum Großteil für die Tonne, weil es einfach für deine Zwecke nicht sinnvoll ist...........
 
  • Gefällt mir
Reaktionen: Sonnenkarma, breedmaster, gaym0r und 3 andere
T_55 schrieb:
Aktuell wird beim Lesen der String aus jeder Zeile zerlegt und dieses Stringfragment zu int/float gewandelt.
Klingt so als wenn du das parsen manuell gebaut hast. Es gibt CSV-Parser/Importer die dir CSV weit effizienter zur Verfügung stellen können. Das klingt gerade so nach der einen Sache die dir dein Problem komplett erschlägt.

Weiterer Gedanke: Wie wäre es mit einer sog. RAM-Disk? Dabei wird ein Teil des RAMs belegt der für dein Betriebssystem bzw. für dich wie eine Festplatte aussieht. Du könntest dann deine Dateien ganz normal da rein 'schieben' und dann ist das alles schon im RAM und du kannst dir das im Programm so laden als wenn das eine normale Datei wäre musst also nichts umcoden.
Du musst dann nur natürlich Ergebnisse stets auf eine echte Platte schreiben, eine RAM-Disk wird natürlich gelöscht wenn der Computer ausgeschaltet wird.

Die Datenmengen auf Platte reduzieren.
What? Besorg dir per Kleinauftrag einfach X TB HDD als Datengrab.
 
Raijin schrieb:
Datenbanken sind genau für diesen Zweck geschaffen, weil sie nicht nur für die Datenspeicherung zuständig sind und dies äußerst effektiv tun, sondern weil sie gleichzeitig Zugriffs- und Suchmechanismen bieten, die du bei einer CSV gar nicht hast.
Das kann man gar nicht oft genug unterstreichen!

Allerdings gibt es bei sehr großen Datensätzen beim Übergang von CSV zu sqlite auch Dinge zu beachten, z.B. wenn man "ungeschickt" hintereinander komplette columns rauszieht und wie sqlite das macht. Was ich meine, ist hier schön dargestellt (allerdings nicht mit C++):
https://pythonspeed.com/articles/indexing-pandas-sqlite/
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: NJay und maxpayne80
@T_55 : Von wie vielen Datensätzen reden wir denn bei der besagten 10 GB CSV? Und wie sieht ein Datensatz konkret aus (mit Beispiel)? Dann kann man besser einschätzen welchen Umfang die ganze Geschichte hat.

@blöderidiot : Klar, auch SQLite hat Grenzen. Letztendlich ist SQLite ja genau das was der TE hier versucht, in Eigenregie aufzubauen, eine große Daten-Datei mit Datenzugriff, aber eben weitestgehend professionell programmiert und nicht mit der heißen Nadel, google und Forum selbst gestrickt.

Im vorliegenden Fall möchte ich fast behaupten, dass diese unsagbar großen CSV-Dateien nicht zustande kommen, weil hier Abermillionen von Datensätzen vorliegen, sondern eher weil eine CSV eben alles als String speichert und somit massiv Speicherplatz verschwendet, weil zum Beispiel bei Zahlen jede Ziffer ein Byte belegt, während sie im korrekten Datentyp - zB INT16 - als ganzes nur zwei belegen würde. Dadurch entstehe ein massiver Overhead an Daten, die bei einer 10 MB Datei nicht wirklich ins Gewicht fallen, aber bei mehreren GigaByte eben schon..............
 
Raijin schrieb:
Im vorliegenden Fall möchte ich fast behaupten,
Das brauchst du nicht behaupten, sondern hat der TE ja selber schon geschrieben ;-):
T_55 schrieb:
Das Einlese-Ziel ist im RAM immer ein vector mit ensprechendem Struct in dem ausschließlich simple Datentypen wie float/int vorkommen. Meistens 12Bytes Struct.
Also sowas wie 4 floats = 12 Byte. Sagen wir z.B. 2-3 Stellen hinter und 2-3 stellen vor dem Komma, dazu das komma plus ein paar semikolons und CR, das wären dann 4*6+4 = 30 Bytes, also das 2,5 fache. Ich würde aber auf mehr tippen, womöglich werden einfach ganz stumpf 10 Stellen hinter dem Komma gespeichert.

Aber der TE scheint ja vor allem das erstmalige Einlesen der CSV (die er ja nun mal so bekommt) in sein Programm beschleunigen zu wollen.
 
BeBur schrieb:
Das brauchst du nicht behaupten, sondern hat der TE ja selber schon geschrieben ;-):
Wobei ich bei dem ganzen Sermon um Komprimierungsalgorithmen, etc, nirgendwo die Information finde von wievielen Datensätzen insgesamt die Rede ist.

Die Überlegungen bezüglich der Komprimierung sind in meinen Augen so oder so hinfällig, wenn man die Daten im dafür vorgesehenen Format abspeichern würde. Du hast es ja schon vorgerechnet was da für ein Platz verschwendet wird. Dass eine CSV mit 5,5 GB mittels 7z auf knapp 300 MB schrumpft, rührt nur zum Teil von der eigentlichen Komprimierung her. Selbst eine unkomprimierte Datenbank mit adäquaten Datentypen wird nur einen Bruchteil des Speicherplatzes der CSV belegen. Deswegen meinte ich ja, dass man es mal mit einem CSV-Import in SQLite ausprobieren könnte, dauert vielleicht 10 Minuten Vorarbeit und dann warten bis der Import durch ist. Wenn da aus 5.5 GB überhaupt noch GigaByte übrig bleiben, würde mich das fast schon wundern.

Wenn man ein konkretes Beispiel eines Datensatzes hätte, könnte man das ja mal realistisch ausrechnen.
 
  • Gefällt mir
Reaktionen: maxpayne80 und BeBur
Zurück
Oben