Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Schnelle DB / Dateibasierend (https://www.delphipraxis.net/166188-schnelle-db-dateibasierend.html)

Jackie1983 2. Feb 2012 10:25

Datenbank: - • Version: - • Zugriff über: -

Schnelle DB / Dateibasierend
 
Servus,

wir haben ein Programm was sehr viele Daten über Sockets bekommt. Diese müssen verarbeitet werden und geloggt. Zur Zeit wird in eine TXT geloggt.

Die log muss komplexer werden. Also habe ich verschiede DB-Systeme (embedded) ausprobiert.

Beim Test war SQLite recht schnell. Ohne Commit nur ein insert kommt man auf 10.000 inserts in 6 Sekunden.

Bei jedem insert müssen die Daten aber auch auf die Platte geschrieben werden. Das Commit braucht einfach zu lange. Da dauert eine Verarbeitung ca. 1 Sekunde, was viel zu lang ist.

Jetzt muss ich eine alternative finden, vielleicht habt ihr noch ideen...

gruß

mkinzler 2. Feb 2012 10:35

AW: Schnelle DB / Dateibasierend
 
Wieviel Einträge kommen den pro Sekunde?

Bernhard Geyer 2. Feb 2012 10:39

AW: Schnelle DB / Dateibasierend
 
ADS ist schnell. Unterstützt aber keine Transaktionen im Embedded Modus. Auch muss man aufpassen ob man bei Verwendung nicht Serverlizenzen benötigt.

mjustin 2. Feb 2012 10:40

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von Jackie1983 (Beitrag 1148841)
Das Commit braucht einfach zu lange. Da dauert eine Verarbeitung ca. 1 Sekunde, was viel zu lang ist.

Jetzt muss ich eine alternative finden, vielleicht habt ihr noch ideen...

Ist die Sekunde zu lang, weil dadurch der Hauptthread blockiert wird und daher keine Daten mehr ankommen?

In diesem Fall einfach die Datenbankoperationen in einen Thread auslagern (oder mehrere, jeweils mit einer Connection pro Client-Thread).

Und man kann die eintreffenden Daten erst mal in einer in-memory Queue speichern, um kurze Spitzenlasten abfangen zu können.

Sind es asynchrone Sockets, die die Haupt-Messageloop verwenden? Auch diesen Bereich könnte man in einen oder mehrere Hintergrundthreads auslagern, mit Indy oder Synapse und blockierenden Sockets wird es dann deutlich einfacher und performanter.

jobo 2. Feb 2012 11:02

AW: Schnelle DB / Dateibasierend
 
Hallo,

falls es noch um das gleiche Thema geht wie neulich. Hier ein nochmal mein Hinweise zu SQLITE und Transaktionen, falls Du das übersehen hast.

http://www.delphipraxis.net/1144412-post11.html

Besorg oder compilier dir eine Version ohne Journaling und Transkationshandling. Brauchst Du ja für s Logging nicht, oder?

Jackie1983 2. Feb 2012 11:14

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von mkinzler (Beitrag 1148843)
Wieviel Einträge kommen den pro Sekunde?

Es kann eh nur eine Nachricht entgegen genommen werden. Wenn diese verarbeitet wurde wird die nächste angenommen. Morgens können schon mal 20.000 Nachrichten kommen. Diese dürfen sich dann aber nicht stauen und müssen alle der Reihe nach bearbeitet werden.

Zitat:

Zitat von Bernhard Geyer (Beitrag 1148845)
ADS ist schnell.

ADS?

Zitat:

Zitat von mjustin (Beitrag 1148846)
Ist die Sekunde zu lang, weil dadurch der Hauptthread blockiert wird und daher keine Daten mehr ankommen?

In diesem Fall einfach die Datenbankoperationen in einen Thread auslagern (oder mehrere, jeweils mit einer Connection pro Client-Thread).

Und man kann die eintreffenden Daten erst mal in einer in-memory Queue speichern, um kurze Spitzenlasten abfangen zu können.

Sind es asynchrone Sockets, die die Haupt-Messageloop verwenden? Auch diesen Bereich könnte man in einen oder mehrere Hintergrundthreads auslagern, mit Indy oder Synapse und blockierenden Sockets wird es dann deutlich einfacher und performanter.

Es kann eh nur ein Auftrag entgegen genommen werden, siehe oben. Verwenden blockierende Sockets.

Kann die Daten aber auch nicht zwischenspeichern oder in einer Queue speichern. Wenn der Rechner abschmiert gehen eventuell 200 Einträge verloren.

mkinzler 2. Feb 2012 11:21

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von mkinzler:
Wieviel Einträge kommen den pro Sekunde?
Es kann eh nur eine Nachricht entgegen genommen werden. Wenn diese verarbeitet wurde wird die nächste angenommen. Morgens können schon mal 20.000 Nachrichten kommen. Diese dürfen sich dann aber nicht stauen und müssen alle der Reihe nach bearbeitet werden.
20.000 in einer Sekunde?
Wie groß ist ein Eintrag?

joachimd 2. Feb 2012 11:29

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von Jackie1983 (Beitrag 1148854)
Zitat:

Zitat von Bernhard Geyer (Beitrag 1148845)
ADS ist schnell.

ADS?

http://www.advantagedatabase.com

Jackie1983 2. Feb 2012 12:04

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von mkinzler (Beitrag 1148856)
20.000 in einer Sekunde?
Wie groß ist ein Eintrag?

Nein Sorry falsch beschrieben. Diese kommen morgens verteilt.

Wie viele pro Sekunde genau kommen kann ich dir nicht sagen. Können bis zu 50 Nachrichten sein.

Jackie1983 2. Feb 2012 12:07

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von jobo (Beitrag 1148849)
Hallo,

falls es noch um das gleiche Thema geht wie neulich. Hier ein nochmal mein Hinweise zu SQLITE und Transaktionen, falls Du das übersehen hast.

http://www.delphipraxis.net/1144412-post11.html

Besorg oder compilier dir eine Version ohne Journaling und Transkationshandling. Brauchst Du ja für s Logging nicht, oder?

Sorry deine Nachricht habe ich übersehen. Ja es geht noch um das gleiche Thema.
Nein das brauche ich nicht.....

p80286 2. Feb 2012 13:19

AW: Schnelle DB / Dateibasierend
 
20000 am Morgen?
das sind dann über den ganz dicken Daumen 3000 pro Stunde. Da ein Stunde aber 3600 Sekunden hat, sollte eine Transaktion pro Sekunde reichen.

Gruß
K-H

Jackie1983 2. Feb 2012 14:29

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von p80286 (Beitrag 1148877)
20000 am Morgen?

Jup. Das heist für eine Nachricht eine Sekunde
20.000 Nachrichten = 20.000 Sekunden = ca 5 Stunden bis die letzte bearbeitet wurde.

Und in der Zeit stauen sich neue Nachrichten an.
Also zulangsam....

shmia 2. Feb 2012 15:36

AW: Schnelle DB / Dateibasierend
 
Man könnte aber auch eine NoSQL Datenbank wie z.B. CouchDB verwenden.
Dabei muss man aber ganz neue Dinge lernen.
Von der Performance und der Flexibilität her ist so etwas aber sehr interessant.

himitsu 2. Feb 2012 15:51

AW: Schnelle DB / Dateibasierend
 
Eventuell statt einem Insert auch mal über ein Append nachdenken.
(hier bei einem MemDataSet dauerte DS.Insert+DS.Post wesentlich länger, als DS.Append+DS.Post)


Privat versuche ich mich grade an Firebird-Embedded zu gewöhnen.

neo4a 2. Feb 2012 16:09

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von Jackie1983 (Beitrag 1148898)
Jup. Das heist für eine Nachricht eine Sekunde
20.000 Nachrichten = 20.000 Sekunden = ca 5 Stunden bis die letzte bearbeitet wurde.

Und in der Zeit stauen sich neue Nachrichten an.
Also zulangsam....

Das Speichern kann immer "zu langsam" sein, auch wenn die DB pfeilschnell arbeitet: Fehler in der Netzwerkverbindung, Windows Update, Virenscanner, DB Maintainance etc.

Um auf der sicheren Seite zu sein, kann eine "2-Phasen-Persistenz" helfen: Einkommende Nachrichten werden zuerst lokal gespeichert (z.B. in einer Log-Datei), um anschließend von dort in die DB übertragen zu werden. Das hat u.a. den Vorteil, dass das transaktionsbasierte SQL-Insert im "Bulk-Mode" wesentlich schneller abläuft, als wenn jeder einzelne Insert commited wird. Beide Prozesse sollten natürlich als Threads oder in getrennten Services/Programmen ablaufen.

Fällt der Client aus, so kann aus der lokalen Log-Datei jederzeit die Übertragung wieder aufgenommen werden.

Dieses Szenario hat sich z.B. bei BDE-Nachrichten-Verarbeitung über viele Jahre hinweg als robust und performant erwiesen.

p80286 2. Feb 2012 16:41

AW: Schnelle DB / Dateibasierend
 
Genau das soll es ja nicht sein,
da die Einträge in die Log-Datei komplexer werden, -was bedeutet das eigentlich?-
soll jetzt in eine DB geschrieben werden.
Mein Schluß daraus, eine Datei zum Vortschreiben der Log-Ereignisse ist untauglich.
(nur verstehen tu ich's nicht)

Gruß
K-H

neo4a 2. Feb 2012 17:00

AW: Schnelle DB / Dateibasierend
 
Zitat:

Zitat von p80286 (Beitrag 1148929)
Genau das soll es ja nicht sein

Sorry, ich habe mich da nicht ganz klar ausgedrückt.

Der erste Prozess schreibt z.B. 10 oder 100 Nachrichten in eine Datei 0001.txt, die nächsten 10 oder 100 in 0002.txt usw. Der 2. Prozess liest 0001.txt, wandelt sie in ein SQL-Script mit Inserts und führt sie aus. Anschließend löscht Prozess 2 0001.txt und macht mit 0002.txt weiter.

Damit mache ich mich bei der Übernahme der Daten unabhängig von deren Weitergabe.

Zur Phase 2: 1000 Datensätze en-bloc sind in eine Firebird-Datenbank in wenigen Sekunden eingefügt, wenn da keine großartigen Trigger etc. mitlaufen. Damit wird die Übernahme von 20000 Datensätzen ein Minuten-Job.

divBy0 2. Feb 2012 18:14

AW: Schnelle DB / Dateibasierend
 
So einen ähnlichen Fall hatte ich auch mal. Über TCP habe ich Nachrichten erhalten und musste diese in eine Datenbank schreiben. Die empfangenen Nachrichten habe ich dann erst mal in einer Datei mittels TFileStream gesichert und dann von dort aus in die Datenbank geschrieben.

Vorteil war, dass keine Nachrichten verloren gegangen sind wenn der Datenbankserver wärend der Inbetriebnahme mal nicht erreichbar war (was öfters vorkam).

himitsu 2. Feb 2012 18:39

AW: Schnelle DB / Dateibasierend
 
Wobei man die ankommenden Daten auch in eine Queue schieben kann. Also analog zu den LogTemp-Dateien.
Dieser Queue/Zwischenspeicher wird dann einfach regelmäßig/kontinuierlich geleert und in die DB übertragen.
Sozusagen alles im RAM, anstatt erst über die HDD zu gehn.

OK, wenn der Rechner, bzw. das Programm abstürzt, dann sind die in der Cache befindlichen Daten natürlich weg,
aber auch diese Temp-Dateien können nach einem Absturz korrupt sein.

Kommt also mehr darauf an, wieviel Zeit der Zwischenspeicher überstehen soll.
- länger und öfters > Datei
- nur kurze Spitzen abfangen > RAM

Furtbichler 2. Feb 2012 22:19

AW: Schnelle DB / Dateibasierend
 
Also ich habe einen Workerthread, der die zu speichernden Daten in einer Stringliste puffert. Der Thread an sich schnappt sich den nächsten String und speichert ihn in der DB. Ich verwende Firebird und komme auf ordentliche 600 Zeilen pro Sekunde. Es ist zwar der Server, aber auf dem selben PC.

Mit dem Puffern im Workerthread kann ich kurzzeitige Spitzen locker abfedern.

Wenn vorher die Sicherheit einer Text-Datei ausreichend war, kann man auch mit Tranksaktionen bzw. gepuffertem Speichern arbeiten, d.h. man sammelt X Daten und bläst die en block (oder in einer Transaktion gekapselt). Ein commit/write wird dann z.B. alle 500ms aufgerufen (sofern daten da sind). Damit sollten noch ein paar 100 Datensätze mehr pro Sekunde verarbeitbar sein.

Peter Pohmann 6. Feb 2012 11:55

AW: Schnelle DB / Dateibasierend
 
Ich habe mal einen kurzen Test mit TurboDB gemacht. Tabelle mit TIMESTAMP, VARCHAR(200), INTEGER auf der lokalen Platte.
Die ersten 1 Mio. Einträge haben ca. 5 Sekunden gedauert.
Die zweite Million ca. 6 Sekunden.
Das alles ohne Transaktionen und Indexe.
Damit Ihr nicht denkt, das wird gepuffert, schließt sich das Programm nach den Einträgen:

for I := 1 to 1000000 do
TdbTable1.AppendRecord([Now, 'alskdfjöasdlfkja sdflökas dföasd fjasdf', 18]);
Close;

Peter


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:29 Uhr.

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