Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS) (https://www.delphipraxis.net/200278-kodieren-gegen-grosses-datenvolumen-datendatei-2-gb-15-mio-ds.html)

Harry Stahl 5. Apr 2019 19:49

Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Nun habe ich ein Update von meinem (einfachen) Datenbank-Programm fertig gestellt (keine große Nummer, eher für einfache Aufgaben und wenig Datenvolumen gedacht). Sollte vorab vielleicht erwähnen, dass ich hier alle Daten im Speicher halte (Stringlisten) und keine besondere Daten-Engine verwende.

Eigentlich wollte ich letzte Woche "nur" mal testen, wie viel Datensätze das Programm aus einer csv-Datei importieren kann (das hat das Release dann noch ein paar Tage verzögert...:?).

Einige 10.000 oder 100.000 ging ja schon vorher, aber wie steht es mit Mio.Datensätzen?

Der erste Versuch, eine 170 MB große Datendatei mit ca. 2,1 Mio. DS zu importieren (in der Windows 32-Bit-Version) scheiterte kläglich an mangelndem Arbeitsspeicher.

OK, da kann man ja noch was optimieren. Den Stream brauch ich doch an Stelle X gar nicht mehr, also warum erst warten mit der Freigabe bis Stelle y, usw...

Die Daten werden in einen Stream eingelesen, der auf bestimmte Dinge überprüft wird und anschließend über eine Stringlist in mein Datenbank-Endformat gebracht (das z.B. aus der 170 MB-Datei dann eine nur noch 70 MB große Datei macht).

Was mir dabei auffiel - und mir jedenfalls nicht bewusst war - welche einfachen "bequemen" Dinge doch viel Arbeitsspeicher kosten:

Ein "if (pos '/sb', slData.text) <> 0" veranlasst Delphi, für (sldata.text) einen extra String zu bauen, der noch mal richtig schön Arbeitsspeicher braucht. Für kleine Datenmengen kein Problem, aber wenn man mehrere 100 MB geladen hat, schon.

Also lieber zeilenweise durch die Liste iterieren und nach dem Teil suchen.

Soweit habe ich das dann tatsächlich hinbekommen, dass ich in der 32-Bit-Version die 2,1 Mio. DS importieren und anzeigen lassen kann (schnell ist das Programm aber dann nicht mehr, in der allgemeinen Anzeige schon, aber in der Filterung von DS nicht, dazu später). Zur Erinnerung: Eine 32-Bit-Version kann nicht mehr als 2 GB Arbeitsspeicher in Anspruch nehmen.

OK und wie viele DS kann das Programm dann in einer 64-Bit-Version laden?

Eine große Datendatei zum freien Download habe ich hier gefunden: https://sdm.lbl.gov/fastbit/data/samples.html

Eben die 2 GB-Datei mit 15 Mio. Datensätzen.

Aber auch hier scheiterte erst mal der Datenimport, weil die Stringliste nicht optimal arbeitet, wenn ein Encoding (UTF-8) auf den Stream angewendet werden soll.

Hier half mir ein Tipp von Uwe (https://www.delphipraxis.net/1316866-post22.html), den ich für meine Bedürfnisse angepasst habe, so dass ich also auch die 2 GB in die Stringliste reinladen kann.

Interessanterweise benötigt die eingelesene Stringliste das 3-4 Fache an Arbeitsspeicher.

Hier fangen meine Fragen an:

* Warum eigentlich? UTF8- ist ja nicht gleich Größe mal zwei sondern eher Größe und ein wenig dazu.
* Gibt es Delphi-Interne Alternativen zur Stringliste (um die Daten zu halten), bzw. externe Lösungen, die nicht soviel Speicher verbrauchen?
* Die Sortierung (mit bis zu 3 keys) mache ich derzeit auch über eine Stringliste, eine TDictionary (das verwende ich für den Primärkey je Tabelle) hilft da nicht weiter, da ich ja nicht doppelte Einträge aufnehmen kann. Gibt es andere schnelle Alternativen für Sotierungen (mit mehreren Schlüsseln)?

Delphi.Narium 5. Apr 2019 20:23

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

... externe Lösungen ...
Datenbank und SQL? Sind extra dafür erfunden worden.

Käme nie auch nur im Ansatz auf die Idee, solche Datenmengen mit Stringlisten ... im Arbeitsspeicher zu verarbeiten. Das muss zwangsläufig irgendwann an Speichermangel scheitern. Und wenn nicht an logischen Speichergrenzen, dann an physikalischen.

Datenbanken können alles das, wonach Du suchst.

Redeemer 5. Apr 2019 20:38

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Platzsparender wäre (falls der Arbeitsspeicher nicht zu fragmentiert ist) TMemoryStream und sich ein TDictionary<Integer, Integer> o.ä. mit Zeilenstartpositionen anzulegen. Da man beim Zeilenstart zwischen ANSI und UTF-8 nicht unterscheiden muss, würde man das Kodieren nach UTF-16LE („WideString“) erst beim Zugriff vornehmen. Schreiben wird aber schwer und insbesondere das Überschreiten von Capacity ein großes Problem.

Vermutlich ebenfalls möglich wäre ein TFileStream (oder TStringReader, wenn der intern auch so funktioniert), der die Dinge in einem Array von RawBawbyteString ablegt, grundsätzlich wäre es aber gut, die Zeilenzahl zu kennen.

Bernhard Geyer 5. Apr 2019 20:39

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1429595)
Zitat:

... externe Lösungen ...
Datenbank und SQL? Sind extra dafür erfunden worden.

:thumb:


Zitat:

Zitat von Delphi.Narium (Beitrag 1429595)
Käme nie auch nur im Ansatz auf die Idee, solche Datenmengen mit Stringlisten ... im Arbeitsspeicher zu verarbeiten. Das muss zwangsläufig irgendwann an Speichermangel scheitern. Und wenn nicht an logischen Speichergrenzen, dann an physikalischen.
Datenbanken können alles das, wonach Du suchst.

Alternativ einfach mal im Bereich der NoSQL-Datenbank nachschauen. Evtl. bieten diese Ja eine alternative zu einer herkömmlichen SQL-Datenbank.
Stichworte wären hier Lucene (Volltextsuche), Graphen-Datenbanken (https://de.wikipedia.org/wiki/Graphdatenbank) oder die "üblichen NoSQL-"Datenbanken" (https://de.wikipedia.org/wiki/NoSQL)

Harry Stahl 5. Apr 2019 22:11

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1429595)
Zitat:

... externe Lösungen ...
Datenbank und SQL? Sind extra dafür erfunden worden.

Käme nie auch nur im Ansatz auf die Idee, solche Datenmengen mit Stringlisten ... im Arbeitsspeicher zu verarbeiten. Das muss zwangsläufig irgendwann an Speichermangel scheitern. Und wenn nicht an logischen Speichergrenzen, dann an physikalischen.

Datenbanken können alles das, wonach Du suchst.

Das ist natürlich schon klar, dass ich mit einer "echten" leistungsfähigen Datenbank-Engine ganz andere Sachen machen kann (wenn man sich denn damit auskennt, das ist ja bei mir das bekannte "Schwarze Loch").

Aber ich habe es ja Anfangs erwähnt, dass das Programm gar nicht für Arbeit mit Mio. DS ausgelegt ist. Wäre aber dennoch interessant, wenn man das zur Not dennoch mal auch mit diesem Programm machen könnte...

Daher die Frage nach Optimierungen. Für die Version 5 kann ich mir dann ja immer noch überlegen, eine richtige DB-Engine zu nehmen...

Harry Stahl 5. Apr 2019 22:13

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von Redeemer (Beitrag 1429596)
Platzsparender wäre (falls der Arbeitsspeicher nicht zu fragmentiert ist) TMemoryStream und sich ein TDictionary<Integer, Integer> o.ä. mit Zeilenstartpositionen anzulegen. Da man beim Zeilenstart zwischen ANSI und UTF-8 nicht unterscheiden muss, würde man das Kodieren nach UTF-16LE („WideString“) erst beim Zugriff vornehmen. Schreiben wird aber schwer und insbesondere das Überschreiten von Capacity ein großes Problem.

Vermutlich ebenfalls möglich wäre ein TFileStream (oder TStringReader, wenn der intern auch so funktioniert), der die Dinge in einem Array von RawBawbyteString ablegt, grundsätzlich wäre es aber gut, die Zeilenzahl zu kennen.

Ja, stimmt, capacity könnte ich auch sinnvoller vorbelegen...

Delphi.Narium 5. Apr 2019 23:13

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von Harry Stahl (Beitrag 1429598)
Das ist natürlich schon klar, dass ich mit einer "echten" leistungsfähigen Datenbank-Engine ganz andere Sachen machen kann (wenn man sich denn damit auskennt, das ist ja bei mir das bekannte "Schwarze Loch").

Aber ich habe es ja Anfangs erwähnt, dass das Programm gar nicht für Arbeit mit Mio. DS ausgelegt ist. Wäre aber dennoch interessant, wenn man das zur Not dennoch mal auch mit diesem Programm machen könnte...

Daher die Frage nach Optimierungen. Für die Version 5 kann ich mir dann ja immer noch überlegen, eine richtige DB-Engine zu nehmen...

Formulieren wir es mal etwas provokant:

Lieber implementierst Du eine eigene Datenbankengine, statt eine vorhandene zu nutzen, da Du Dir die Nutzung einer vorhandenen als "schwarzes Loch" vorstellst.

Bin mal so vermessen zu behaupten: Die Beseitigung des "schwarzen Loches" ist weniger aufwändig, als eine sinnvolle und funktionierende Implementierung dessen, was Du vorhast.

Das Schreiben einer Datenbankanwendung mit Delphi ist so banal einfach, dass man da nichtmal wirklich DB-Knowhow haben muss.

Harry Stahl 5. Apr 2019 23:30

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Auf die "richtige" DB-Anwendung werde ich mich später mit Sicherheit mit Freuden drauf stürzen. Momentan kommt mir es aber dennoch auf eine weitere Optimierung der Effizienz und Geschwindigkeit der aktuellen Programmfassung an.

Was ich vorhatte, habe ich mit meiner aktuellen Lösung 100% erfüllt (DB-Programm, das bei Verwendung von Datensätzen um die 100.000 herum absolut zügig und effizient zu verwenden ist und alle Anforderungen (incl. relationales Datenbankmodell, berechnete Felder, Import und Export relevanter Formate, Abfragen, etc., nutzbar auf 5 Plattformen (Windows, MAC, Linux, IOS und Android)) unterstützt.

Als das hier alles so mit der Plattformübergreifenden Entwicklung los ging, war ich froh, dass ich meine eigene Lösung hatte, denn anderweitig gab es ja erst mal nicht so viel. Außerdem ist meine Lösung extrem flach und einfach zu verwenden und leicht anpassbar, insofern macht es absolut Sinn, sich so etwas vorzuhalten.

Die Optimierungs-Tipps im Zusammenhang mit dem Umgang mit großen Datenvolumen kann man sicher auch noch anderweitig verwenden.

Ich denke, auch für eine der "normalen" Delphi SQL-Datenbanken muss eine eigene csv-Import-Routine geschrieben werden, oder gibt es da schon Lösungen, die alle so denkbaren Varianten (Linux / Windows Dateiformate, String-Kodierungen / Plattformen) abdeckt?

Delphi.Narium 6. Apr 2019 00:28

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Wüsste jetzt nicht, dass ich jemals für 'ne Datenbankanwendung 'nen CSV-Import benötigt habe.

In der ODBC-Verwaltung findet man z. B. auch "Treiber" für CSV-Dateien, das ist dann wohl nicht zwingend plattformunabhängig. Man kann damit aber auf CSV-Dateien in der gleichen Form zugreifen, wie auf alle übrigen Datenbanken. Für die Datenbankkomponenten ist das absolut transparent.

Wenn man z. B. die Zeoslib-Datenbankkomponenten (oder vermutlich auch alle anderen Datenbankkomponenten) nutzt, so muss man nur in der Komponente, die für die Verbindung zur Datenbank zuständig ist, angeben, um was für eine Datenbank es sich handelt. Alle anderen Komponenten sind davon nicht betroffen.

Lediglich durch Änderung dieser Konfigurationsparameter kann man einem Programm eine "andere Datenbank unterschieben". Natürlich kann man das auch über eine Konfigurationsdatei, 'nen Konfigurationsdialog (o. ä.) steuern, so dass man ein Programm so implementieren kann, dass ihm die darunterliegende Datenbank schlicht egal ist.

Und damit hat man dann auch Plattformunabhängigkeit.

Man schreibe das Programm so, dass man über eine Konfiguration die Datenbank wählt und kann dann auf jeder Plattform die Datenbank verwenden, die dort am besten geeignet ist.

Zum Datenbankwechsel ist (bei halbwegs intelligenter Programmierung) kein Neukompilieren des Programmes nötig.

Wenn ich mal 'ne Datenbankanwendung brauche, ohne 'ne Datenbank zu nutzen, nehme ich dafür KbmMemTable. Das sind Textdateien mit 'nem Header, in dem im Klartext steht, wie der Inhalt der Datei aufgebaut ist, was es so an Index gibt ...
Die Daten sind je Datensatz in einer Zeile, die von Aufbau und Struktur einer CSV-Datei entspricht.

Der Zugriff auf diese Dateien erfolgt über eine Schnittstellen-/Konfiguratinskomponente und damit verbundene, von TDataSet abgeleitete, Komponente. Die kann man im Quelltext genauso nutzen, wie jede beliebige andere Datenbankkomponente auch.

Damit könntest Du vermutlich Dein Eingangsproblem auch lösen, da alle Deine Anforderungen auch von diesen Komponenten erfüllt werden. Das Handling ist aber sicherlich einfacher, als mit Stringlisten ...

Thomas Horstmann 6. Apr 2019 10:16

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Wie entwickeln Datenbanken die auch mal mehrere Milliarden Datensätze enthalten können. Unser System ist zwar multidimensional aufgebaut aber die Probleme sind wahrscheinlich ähnlich. Es hat sich gezeigt, das die Standardkomponenten wie TStringList, TDictionary usw. für so etwas nicht ausgelegt sind. Auch Tricks wie TList.Capacity bringt nicht viel. Deshalb wurde alles ziemlich weit unten neu "aufgebaut". Auch auf TObject wurde verzichtet, da der Overhead (Geschwindigkeit und Speicher) im Vergleich zu TRecord zu groß ist. D.h. es blieb nur noch TRecord, Arrays, Pointer und selber QuickSort Routinen schreiben (zum Suchen und Einfügen). Und an einigen kritischen Stellen ASM verwenden. Damit läuft es aber sehr ordentlich. Also eher "back to the basics" :-)

Harry Stahl 6. Apr 2019 11:56

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von Thomas Horstmann (Beitrag 1429613)
Wie entwickeln Datenbanken die auch mal mehrere Milliarden Datensätze enthalten können. Unser System ist zwar multidimensional aufgebaut aber die Probleme sind wahrscheinlich ähnlich. Es hat sich gezeigt, das die Standardkomponenten wie TStringList, TDictionary usw. für so etwas nicht ausgelegt sind. Auch Tricks wie TList.Capacity bringt nicht viel. Deshalb wurde alles ziemlich weit unten neu "aufgebaut". Auch auf TObject wurde verzichtet, da der Overhead (Geschwindigkeit und Speicher) im Vergleich zu TRecord zu groß ist. D.h. es blieb nur noch TRecord, Arrays, Pointer und selber QuickSort Routinen schreiben (zum Suchen und Einfügen). Und an einigen kritischen Stellen ASM verwenden. Damit läuft es aber sehr ordentlich. Also eher "back to the basics" :-)

Ja, danke das sind Erfahrungsberichte, die ich sehr interessant finde. Habe mir schon so was gedacht.

Wie gesagt, meine jetzige Lösung ist nur eine "kleine" Lösung, aber für die Version 5 im nächsten Jahr will ich dann doch auch große Datenmengen (> 100 Mio. oder mehrere Mrd) zügig verarbeiten können.

Habt Ihr dann ganz auf die "typischen" SQL-DB's verzichtet und eine eigene Lösung gebastelt?

Und selbst das TDictionary haltet Ihr nicht für geeignet? Wegen des Anlegens der Sammlung oder Speicherverbrauch? An der Geschwindigkeit könnte es doch eher nicht liegen, oder?

Die vorgetragenen Argumente pro SQL sind mir alle einleuchtend, dennoch hänge ich ein wenig an eigenen Lösungen, da die oft sehr viel mehr Flexibilität für "Sonderwünsche" bieten.

dummzeuch 6. Apr 2019 12:46

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Wenn in den Daten viele Strings doppelt vorkommen, hilft vielleicht String Interning. Das hat mir mal sehr geholfen, den Speicherbedarf einer Anwendnung zu reduzieren. Dadurch werden doppelte Strings zu einem einzigen zusammengefasst, der dann entsprechnend einen höheren Referenzzähler hat.

Eine Implementation auf Basis einer Stringlist findest Du z.B. in meiner dzlib. Die ist allerdings noch für AnsiStrings entwickelt und mit UnicodeStrings nicht getestet.

Thomas Horstmann 6. Apr 2019 12:52

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Unsere Datenbank ist multidimensional und da läuft die Speicherung anders wie in der relationalen Wert. Eine Tabelle besteht nicht aus einem großen "Array", sondern aus viele kleinen, die untereinander per Pointer verbunden sind. Ggf. werden diese Konstrukte dann Milliarden mal durchlaufe, so dass es "unten" auf jedes if/then/else ankommt. Und 10% mehr Speicher oder weniger Geschwindigkeit ist dann schon ein Ausschlusskriterium. Wir haben einiges getestet und alles ab TObjekt war nicht brauchbar.

Aber das ist auch der Vorteil von Delphi; es ist relativ alt und systemnah. Strukturen wie Array, Pointer, Record usw. kommen aus einer Zeit als CPU und Speicher knapp waren. Da musst alles extrem optimiert werden. Und dem Kunden heute kann es "grundsätzlich" nie schnell genug gehen.

Harry Stahl 10. Apr 2019 21:06

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von dummzeuch (Beitrag 1429628)
Wenn in den Daten viele Strings doppelt vorkommen, hilft vielleicht String Interning. Das hat mir mal sehr geholfen, den Speicherbedarf einer Anwendnung zu reduzieren. Dadurch werden doppelte Strings zu einem einzigen zusammengefasst, der dann entsprechnend einen höheren Referenzzähler hat.

Eine Implementation auf Basis einer Stringlist findest Du z.B. in meiner dzlib. Die ist allerdings noch für AnsiStrings entwickelt und mit UnicodeStrings nicht getestet.

Interessante Idee, nur kommen hier im Prinzip keine doppelten Strings vor, da jeder String mit einem eindeutigen ID versehen ist (somit ist jeder String anders).

Aber dennoch interessant, evtl. kann man es ja mal bei einer anderen Gelegenheit verwenden.

Harry Stahl 10. Apr 2019 21:35

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von Redeemer (Beitrag 1429596)

Vermutlich ebenfalls möglich wäre ein TFileStream (oder TStringReader, wenn der intern auch so funktioniert), der die Dinge in einem Array von RawBawbyteString ablegt, grundsätzlich wäre es aber gut, die Zeilenzahl zu kennen.

Tfilestream zu verwenden war eine gute Idee fürs Laden und Speichern der eigenen Datendatei, da ich so das zusätzliche Anlegen von großen TMemorystreams vermeiden kann. Wenn die DB verschlüsselt ist, muss ich allerdings doch wieder TMemorystream verwenden, da das verschlüsseln und entschlüsseln auf einem TFilestream zu langsam ist. Letztlich aber nicht so schlimm, da ich die Verschlüsselung immer nur auf eine komprimierte Datei anwende, die ist deutlich kleiner als die eigentliche Datenmenge und das dekomprimieren der entschlüsselten Datei geht zügig genug mit dem Filestream.

Mit den ganzen Optimierungen ist es mir jetzt immerhin gelungen (in der Windows 64-Bit bzw. Linux-64-Bit-Version mit mindestens 16 GB RAM) die 2,1 GB große csv-Datei mit über 15 Mio. Datensätzen zu importieren und in meinem komprimierten Datenformat zu speichern (dann werden da ca. 600 MB draus). Wie gesagt, arbeiten kann man damit dann nicht mehr flüssig (z.B. die "Life"-Filterung wird dann extrem hakelig und laden und speichern dauert z.B. einige Sekunden), also nach wie vor bleibt es bei der Zielgruppe der User, die nicht mehr als 100.000 - 200.000 DS mit dem Programm bearbeiten müssen. Hat aber einfach Spaß gemacht, die Leistungsgrenzen mal ein wenig aufzubohren und ein wenig mehr Gefühl dafür zu bekommen, bei welchen Aktionen u.U. schnell ein großer Speicherverbrauch auftreten kann.

Letztlich hat das auch dazu geführt, dass ich unter Windows erstmals eine 64-Bit-Version eines Programm veröffentlicht habe, denn mit dem Wegfall der 2 GB Speichergrenze in der 64-Bit-Programmfassung kommt man in diesem Fall dann doch deutlich weiter... (wäre schön, wenn Delphi - das ja auch noch ein 32-Bit-Programm ist - da gleichfalls mal bald nachziehen würde...:wink:)

jobo 11. Apr 2019 07:13

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Also erstmal mein Kompliment zur Optimierung der Anwendung. Diese Mühen nimmt selten jemand auf sich. Der Anlaß trübt allerdings meine Begeisterung etwas. Ich hab zu dem Thema "3" Punkte:
- Bei Deinen Optimierungen sollte Dir klar sein, dass Deine Anwendung ggF. nicht die einzige auf dem PC ist. Datensatzzahlen bzw. Verarbeitungsgeschwindigkeit sind also vielleicht trügerisch.
- Zum empfohlenen Einsatz von Datenbanken und deinen Worten von der Verarbeitung von Milliarden Datensätzen: Der Einsatz einer DB Engine macht aus einem Desktop (oder Racksystem) keinen Quantencomputer. Das Prinzip beruht hauptsächlich auf der gezielten und kleinteiligen Verarbeitung eines Datenausschnitts. Also große "Festplatte", optimierter Zugriff, kleine OPs. Solltest du wirklich in die Verlegenheit kommen, Milliarden Daten zu >verarbeiten<, wirst Du schnell die Grenzen dieser Systeme kennenlernen.
- SQL als Standard ist leider schwierig. Sobald Du in der Anwendung Query Komponenten verwendest, kommt wahrscheinlich irgendwann der Punkt, wo Du proprietäre Syntax verwendest, besonders bei der "Verarbeitung von Milliarden DS". Performancebedarf wird in SQL häufig mit proprietären Lösungen gedeckt. Allein die Vielfalt der existierenden Systeme (Deins inkl.) und die Verschiedenheit der Ansätz (noSQL, ..) spiegeln den recht unterschiedlichen Bedarf und eben die Lösungswege.
- CSV kann heute fast jede DB Engine von sich aus einlesen.

Ich habe bei der Schilderung deiner Situation an ORM Systeme denken müssen. Damit kannst Du vielleicht eine ggute Trennschicht zwischen Dein (gewohntes) System und die DB ziehen. Außerdem musste ich an die Arbeit von @haentschman denken, mit ihm solltest du vielleicht mal ein Bier trinken gehen.

mkinzler 11. Apr 2019 08:06

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Das ist natürlich schon klar, dass ich mit einer "echten" leistungsfähigen Datenbank-Engine ganz andere Sachen machen kann (wenn man sich denn damit auskennt, das ist ja bei mir das bekannte "Schwarze Loch").
Dann bleibe ja noch der Zwischenweg: ORM. Der Zugriff auf Datenbanekn über Nicht-Datenbank-Strukturen.

TiGü 11. Apr 2019 08:16

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Du könntest noch ein bisschen mit der neuen Möglichkeit spielen, deine eigene Wachstumsstrategie für Collection-Klassen zu implementieren.
Wenn dir im Vorfeld die maximale Größe der Datenstrukturen bekannt ist und du die vor dem Füllen setzen kannst, dann kannst du das neu allozieren und umkopieren des darunterliegenden Arrays im Grenzbereich sparen.
Ein paar Prozent mehr Speicheroptimierung und/oder Performance lässt sich vielleicht rausschinden.

http://blog.marcocantu.com/blog/2018...ments-rio.html
http://docwiki.embarcadero.com/Libra...CollectionFunc

Harry Stahl 12. Apr 2019 14:54

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von jobo (Beitrag 1430037)
Also erstmal mein Kompliment zur Optimierung der Anwendung. Diese Mühen nimmt selten jemand auf sich. Der Anlaß trübt allerdings meine Begeisterung etwas. Ich hab zu dem Thema "3" Punkte:
- Bei Deinen Optimierungen sollte Dir klar sein, dass Deine Anwendung ggF. nicht die einzige auf dem PC ist. Datensatzzahlen bzw. Verarbeitungsgeschwindigkeit sind also vielleicht trügerisch.
- Zum empfohlenen Einsatz von Datenbanken und deinen Worten von der Verarbeitung von Milliarden Datensätzen: Der Einsatz einer DB Engine macht aus einem Desktop (oder Racksystem) keinen Quantencomputer. Das Prinzip beruht hauptsächlich auf der gezielten und kleinteiligen Verarbeitung eines Datenausschnitts. Also große "Festplatte", optimierter Zugriff, kleine OPs. Solltest du wirklich in die Verlegenheit kommen, Milliarden Daten zu >verarbeiten<, wirst Du schnell die Grenzen dieser Systeme kennenlernen.
- SQL als Standard ist leider schwierig. Sobald Du in der Anwendung Query Komponenten verwendest, kommt wahrscheinlich irgendwann der Punkt, wo Du proprietäre Syntax verwendest, besonders bei der "Verarbeitung von Milliarden DS". Performancebedarf wird in SQL häufig mit proprietären Lösungen gedeckt. Allein die Vielfalt der existierenden Systeme (Deins inkl.) und die Verschiedenheit der Ansätz (noSQL, ..) spiegeln den recht unterschiedlichen Bedarf und eben die Lösungswege.
- CSV kann heute fast jede DB Engine von sich aus einlesen.

Ich habe bei der Schilderung deiner Situation an ORM Systeme denken müssen. Damit kannst Du vielleicht eine ggute Trennschicht zwischen Dein (gewohntes) System und die DB ziehen. Außerdem musste ich an die Arbeit von @haentschman denken, mit ihm solltest du vielleicht mal ein Bier trinken gehen.

Ja, das mit den Mrd. Datensätzen war vielleicht auch ein wenig hoch gegriffen...

SQL finde ich sehr interessant, wie man mit recht einfachen Sprachkonstrukten Auswahlen von Daten bzw. neue Tabellen anlegen kann. Sehr schön, schon beschlossene Sache, dass ich in Version 5 die wesentlichen SQL-Befehle als Alternative zu meiner eigenen Lösung unterstützen werde.

Harry Stahl 12. Apr 2019 15:03

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von TiGü (Beitrag 1430040)
Du könntest noch ein bisschen mit der neuen Möglichkeit spielen, deine eigene Wachstumsstrategie für Collection-Klassen zu implementieren.
Wenn dir im Vorfeld die maximale Größe der Datenstrukturen bekannt ist und du die vor dem Füllen setzen kannst, dann kannst du das neu allozieren und umkopieren des darunterliegenden Arrays im Grenzbereich sparen.
Ein paar Prozent mehr Speicheroptimierung und/oder Performance lässt sich vielleicht rausschinden.

http://blog.marcocantu.com/blog/2018...ments-rio.html
http://docwiki.embarcadero.com/Libra...CollectionFunc

In Delphi 10.3 ist wohl "Dictonary.Tryadd" neu / optimiert worden, bringt noch 100-200 ms bei ca. 2 Mio DS (statt if not Dictionary.contains, then add).

Was ich festgestellt habe, was viel Zeit kostet, ist die Sortierung der Stringlisten, wenn nach Textinhalten sortiert werden soll. Insbesondere, wenn (was ja Standard ist) Stringlist.uselocale auf True ist. Bei deutschen Textinhalten (Umlaute!) braucht man das aber leider, kann man aber ausschalten, wenn nur auf ein Integer-Feld sortiert wird und keine 2 oder 3. Text-Sortierfeld verwendet wird.

Wenn .Uselocale aktiv ist, wird in "TStrings.Comparestrings" die Funktion "AnsiCompareText" (statt sonst "CompareText") verwendet, was recht langsam ist (12 Sekunden, statt 4 Sekunden mit CompareText).

Gibt es dazu keine bessere Lösung?

Blup 17. Apr 2019 09:48

AW: Kodieren gegen großes Datenvolumen (Datendatei > 2 GB, > 15 Mio. DS)
 
Zitat:

Zitat von Harry Stahl (Beitrag 1429593)
Soweit habe ich das dann tatsächlich hinbekommen, dass ich in der 32-Bit-Version die 2,1 Mio. DS importieren und anzeigen lassen kann (schnell ist das Programm aber dann nicht mehr, in der allgemeinen Anzeige schon, aber in der Filterung von DS nicht, dazu später).

Es ist nicht sinnvoll so viele Datensätze im Arbeitsspeicher zu halten.
Es gibt bessere Konzepte z.B.:

Vorbereitung:
- temporäre Datenbank erzeugen
- Tabelle mit den Spalten der CSV-Datei anlegen
- CSV-Datei in die Tabelle einlesen
- jeweils einen Index auf Spalten setzen, die gefiltert oder sortiert werden können
Anzeige:
- je nach Filter/Sortierung die SQL-Anfrage anpassen
- die Anzahl der anzuzeigenden Datensätze ermitteln und Anzeige vorbereiten (z.B. TDrawGrid.RowCount)
- nur die Datenzeilen lesen, die tatsächlich gerade im Fenster sichtbar sind (z.B. Zeile 1- 150) (Daten für die Anzeige bereitstellen z.B. TDrawGrid.OnGetEditText)
- beim Scrollen die nicht mehr sichtbaren Daten aus dem Speicher entfernen und die sichtbaren Daten nachladen (z.B. Zeile 100 - 250)
Import:
- Daten auf Datenbankebene verarbeiten (SQL-Befehle) oder Zeile für Zeile

Zitat:

Zitat von Harry Stahl (Beitrag 1429593)
Zur Erinnerung: Eine 32-Bit-Version kann nicht mehr als 2 GB Arbeitsspeicher in Anspruch nehmen.

Das ist nicht ganz richtig. Mit diesem Flag sind je nach Betriebsystemumgebung bis zu 4 GB Arbeitsspeicher direkt adressierbar.
Delphi-Quellcode:
{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}

{$R *.res}

begin
  Application.Initialize;
{...}


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:06 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz