Autor Beitrag
doublecross
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 149
Erhaltene Danke: 27

Windows 7
C#; Visual Studio 2015
BeitragVerfasst: Fr 06.01.17 17:44 
Hallo,

ich suche eine "best practice" für folgendes Problem und hoffe, dass der eine oder andere Erfahrung damit hat.

Gegeben sei eine Postgresql-Datenbank mit den folgenden Tabellen:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
       Products
-----------------------
Key            : Int
ID             : Int
Name           : text
manufacturerid : int  


     Location
-----------------
Key        : int
ID         : Int
Name       : text 


         Movement
-----------------------------
Time            : timestamp
ProductKey      : int
FromLocationKey : int
ToLocationKey   : int


Diese Tabellen werden über mehrere Clients im Netzwerk gefüllt, welche Ihrerseits Dateien von Drittanbiterprogrammen verarbeiten. Diese Dateien sind in etwa so aufgebaut:

ausblenden XML-Daten
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
<movemenr>
  <timestamp>2017-01-06T16:08:00</timestamp>
  <product>
    <ID>4711</ID>
    <Name>Babelfisch</Name>
    <manufacturerid>0815</manufacturerid>
  </product>
  <from>
    <ID>37</ID>
    <Name>Stock 53</Name>
  </from>
  <to>
    <ID>61</ID>
    <Name>Factory 7</Name>
  </to>
</movemenr>


Es enthält also jedes Movement alle Informationen zum Produkt und den Locations. Hierüber wird auch die Datenanlage in der Postgresql Datenbank erledigt, sprich, wenn ein Produkteintrag erkannt wird, so wird in der Datenbank überprüft, ob bereits ein Produkt mit der selben ID, Namen und HerstellerId vorhanden ist. Ist dies nicht der Fall, so wird ein neuer Eintrag angelegt und ein neuer Key erzeugt (Hausinterne ID - AutoInc). Da die Daten aus unterschiedlichen Quellen stammen, kann es vorkommen, dass zwei unterschiedliche Produkte die gleiche ID und HerstellerID besitzen, sich aber im Namen unterscheiden, daher werden alle Einträge mit einem Hausinternen Key versehen und dieser in der Movment-Tabelle verwendet um den Stammdatensatz zu referenzieren.

So weit so klar.

Die Dateien, die von den Clients verarbeitet können mehrere hundert bis ein paar tausend Movements enthalten, um sowohl die Datanbankzugriffe halbwegs flott zu halten und auch keine Scherereien mit halb verarbeiteten Dateien im Falle z. B. eines Stromausfalles zu bekommen, werde immer alle zu einer Datei gehörigen Datenbankaktionen in einer Transaktion gesammelt, welche Commited wird, sobald die Datei vollständig abgearbeitet ist. Auch das funktioniert eigentlich ganz gut, bis auf einen Sonderfall: Wenn zwei Clients "gleichzeitig", eine Datei auswerten, und in dieser "der gleiche" neue Artikel enthalten ist, so stellen beide Clients fest, dass er neu ist, legen ihn an und erhalten dabei unterschiedliche interne Keys (wahrscheinlich direkt aufeinander folgende Nummern). Sobald also beide Clients ihr Commit geschickt haben habe ich zwei Einträge für das gleiche Produkt in der Datenbank aber zwei verschiedene Keys dafür generiert, das möchte ich aber vermeiden.

Ich suche also eine Strategie, mit der ich:
  1. Neue Datensätze anlegen kann wenn sie noch nicht existieren (ansonsten den Key des Bestehenden Datensatzes erfragen)
  2. Ich erkennen kann ob gerade ein anderer "Kunde der Datenbank" den gleichen Datensatz anzulegen gedenkt
  3. Ich wenn dies der Fall ist den gleichen Key erhalte, den die Datenbank für den andere Client erzeugt hat
  4. Der Datensatz immer erzeugt wird, wenn einer der Beiden Clients ein Commit schickt (egal welcher) falls es auf dem anderen zu einem Rollback kommt
  5. Der Datensatz maximal 1x angelegt wird
  6. Der Datensatz nicht angelegt wird, wenn alle Clients einen Rollback machen


Hierbei ist der einzige Berührungspunkt für die Clients die Datenbank selbst.

Kennt jemand von euch gute Strategien um das Problem anzugehen?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 06.01.17 18:17 
Eine gute Strategie hängt zusammen mit bestimmten Häufigkeiten damit man das System in die richtige Richtung optimiert. Solche Optimierungen führen meist dazu das andere Dinge im System dann weniger gut funktionieren als bisher. Insofern ist es wichtig da eine ziemliche genaue Vorstellungen zu haben.

Wie wahrscheinlich ist das ein Datensatz neu ist gegenüber dem das er bereits da ist?
Wie wahrscheinlich ist der Fall kollidierenden Inserts (also das 2 gleiche Datensätze gleichzeitig importiert werden)

Nebenbei gefühlt sehe ich da keinerlei Möglichkeit es gleichzeitig korrekter und schneller zu machen wenn die Imports im Moment auf mehrere langlaufende parallele Commits hinauslaufen (so hatt eich das jetzt zumindest verstanden). Zumindest solange da jetzt nicht irgendein anderer Bock drin ist denn man beseitigen könnte.
icho2099
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 101
Erhaltene Danke: 12

WIN XP, WIN 7, WIN 10
Delphi 6 Prof, Delphi 2005, FPC
BeitragVerfasst: So 08.01.17 14:48 
Hallo, in einem ähnlich gelagerten Fall habe ich alle neuen Datensatzes zunächst in eine Vorerfassungstabelle geladen. Da sind dann auch Duplikate aufgetaucht. In einem zweiten Schritt wurde diese Tabelle in die Zieltabelle übertragen. Dabei werden Duplikate erkannt und aussortiert.
doublecross Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 149
Erhaltene Danke: 27

Windows 7
C#; Visual Studio 2015
BeitragVerfasst: Mo 09.01.17 18:01 
Hallo,

user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Wie wahrscheinlich ist das ein Datensatz neu ist gegenüber dem das er bereits da ist?
Wie wahrscheinlich ist der Fall kollidierenden Inserts (also das 2 gleiche Datensätze gleichzeitig importiert werden)


die ist am Anfang (Standatemsätze noch leer) sicherlich höher als später im Regelbetrieb, bei Testläufen ist der Fall aber bereits aufgetreten.


user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Nebenbei gefühlt sehe ich da keinerlei Möglichkeit es gleichzeitig korrekter und schneller zu machen wenn die Imports im Moment auf mehrere langlaufende parallele Commits hinauslaufen (so hatt eich das jetzt zumindest verstanden). Zumindest solange da jetzt nicht irgendein anderer Bock drin ist denn man beseitigen könnte.


Ich sehe da leider auch noch keine "gute" Lösung, ich hoffe da noch irgend eine super duper PostgreSQL Server Technik zu übersehen, die mir hier raus hilft.


user profile iconicho2099 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo, in einem ähnlich gelagerten Fall habe ich alle neuen Datensatzes zunächst in eine Vorerfassungstabelle geladen. Da sind dann auch Duplikate aufgetaucht. In einem zweiten Schritt wurde diese Tabelle in die Zieltabelle übertragen. Dabei werden Duplikate erkannt und aussortiert.


Einen ähnlichen Ansatz, allerdings im Form dass ich Duplikate direkt aus der Zieltabelle Herausoptimiere, hatte ich auch schon überlegt, allerdings sehe ich solche "end of pipe" Lösungen immer als letzten Ausweg schöner wäre es direkt zu verhindern, dass die Duplikate überhaupt angelegt werden.

Eine weitere Idee die ich hatte war es, neue Stammdatensätze an der Transaction vorbei sofort anzulegen, aber dann müsste ich im Nachhinein auch wieder diejenigen löschen, zu denen es keine Bewegungsdaten gibt (Rollback aus irgend einem Grund). Hätte also wieder ein ähnliches Problem.

Auf jeden Fall schon einmal danke für eure Vorschläge und Kommentare!
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 09.01.17 21:14 
Zitat:
Ich sehe da leider auch noch keine "gute" Lösung, ich hoffe da noch irgend eine super duper PostgreSQL Server Technik zu übersehen, die mir hier raus hilft.


Ich sehe da eher ein logisches produktunabhhängiges Problem wenn es langlaufende parallele Transaktionen sind. Das lässt sich eher nicht durch clevere Technik lösen.
Dann müßtest du schon ganz anders ansetzen und überlegen wie du das in kleinere trotzdem in sich vollständige Transaktionen zerlegen kannst.

Vielleicht müsstest du nochmal dein angesprochenes Problem mit halb verarbeiteten Dateien aufdrösseln. Warum ist das ein Problem? Ist das wirklich ein Problem? Du scheinst ja eh eine Dulpikatserkennung zu brauchen. Die sollte doch dann auch ziehen wenn man die gleiche Datei nochmal importiert. Also sollte man doch Transaktionen eigentlich auch auf kleiner Einheiten ausführen können. Und im Zweifel den Import der gleichen Datei problemlos wiederholen können. Eine solche Situation sollte ja auch eher selten sein.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mo 09.01.17 22:47 
Hey, ich habe so ein ähnliches Problem so gelößt dass immer nur ein Module zur gleichen Zeit Aktionen durchführen kann. Als zweiten Schritt haben Transaktionen eine so kurze Laufzeit wie irgend möglich um das blockieren der anderen Nutzer zu verhindern.
Ich habe in meinem Fall mehrere Nutzer die einzelne Datensätze einfügen oder bearbeiten und einen Nutzer der dies massenhaft tut.
Nutzer können erst bis zu einem Punkt parallel arbeiten, versuchen sich dann das Recht für exclusive Aktionen zu hohlen. Dann werden die Daten validiert und abgesendet. Ist jemand anderes im Weg wird der Nutzer informiert. Er kann warten oder seine Eingaben später nocheinmal wiederhohlen.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
doublecross Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 149
Erhaltene Danke: 27

Windows 7
C#; Visual Studio 2015
BeitragVerfasst: Di 10.01.17 12:18 
Hallo,
user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Vielleicht müsstest du nochmal dein angesprochenes Problem mit halb verarbeiteten Dateien aufdrösseln. Warum ist das ein Problem? Ist das wirklich ein Problem?

das ist eher ein Psychologisches Problem. Die Import Dateien werden vom Nutzer als eine Einheit gesehen (alle Aktionen eines Tages an einem Standort) wenn davon plötzlich nur die Hälfte verarbeitet wurde wird das als schlimmerer Fehler wahrgenommen, als wenn gar nichts verarbeitet wurde, da letzterer Fall direkt ersichtlich ist (und ja natürlich gibt es auch deutliche Warnungen wenn Dateien nicht zur Gänze Importiert werden aber was kann m an gegen die Wahrnehmung des Nutzers tun?). Technisch wäre es also sogar möglich die Transaktionen kleiner zu halten, es wäre aber schwer zu vermitteln.

user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Du scheinst ja eh eine Dulpikatserkennung zu brauchen. Die sollte doch dann auch ziehen wenn man die gleiche Datei nochmal importiert. Also sollte man doch Transaktionen eigentlich auch auf kleiner Einheiten ausführen können. Und im Zweifel den Import der gleichen Datei problemlos wiederholen können. Eine solche Situation sollte ja auch eher selten sein.

Zum einen bemühe ich mich diese nur bei den Stammdaten, nicht aber bei den Bewegungsdaten anzuwenden (diese verursacht ja auch [zeit] Kosten). Zum anderen würde eine Beschleunigung des ganzen das Risiko nur minimieren aber nicht ausschließen.



user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Hey, ich habe so ein ähnliches Problem so gelößt dass immer nur ein Module zur gleichen Zeit Aktionen durchführen kann. Als zweiten Schritt haben Transaktionen eine so kurze Laufzeit wie irgend möglich um das blockieren der anderen Nutzer zu verhindern.
Ich habe in meinem Fall mehrere Nutzer die einzelne Datensätze einfügen oder bearbeiten und einen Nutzer der dies massenhaft tut.
Nutzer können erst bis zu einem Punkt parallel arbeiten, versuchen sich dann das Recht für exclusive Aktionen zu hohlen. Dann werden die Daten validiert und abgesendet. Ist jemand anderes im Weg wird der Nutzer informiert. Er kann warten oder seine Eingaben später nocheinmal wiederhohlen.


Ich müsste einmal darüber nachdenken ob sich ein solches Modell auf meine Automatische Verarbeitung übertragen lässt. Ich müsste im Grunde die Stammdatentabellen Exklusiv locken, und im Gegenzug dieses Locking so kurz wie möglich halten. Das dürfte ich aber erst dann tun, wenn ich weiß, dass ich die jeweilige Datei komplett auswerten konnte. Das wiederum bedeutet, ich kann die Verlinkten Keys erst am Ende der Verarbeitung kennen.

Wenn ich das weiter denke würde es darauf hinauslaufen, dass ich aus den Dateien erst einmal eine Im Memory Datenstruktur bauen müsste, welche ich dann im Nachhinein, nachdem die Stammdaten in der Datenbank abgelegt wurden, mit den richtigen Keys füttere, bevor ich die Transaktionen für die Bewegungsdaten fahren kann.

Da muss ich mal in mich gehen um zu sehen ob mir das Gefällt und ob die Speicherauslastung auf den Clients dadurch nicht zu sehr wächst.

Danke noch einmal für die Denkanstöße.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Di 10.01.17 13:33 
user profile icondoublecross hat folgendes geschrieben Zum zitierten Posting springen:
Ich müsste einmal darüber nachdenken ob sich ein solches Modell auf meine Automatische Verarbeitung übertragen lässt. Ich müsste im Grunde die Stammdatentabellen Exklusiv locken, und im Gegenzug dieses Locking so kurz wie möglich halten. Das dürfte ich aber erst dann tun, wenn ich weiß, dass ich die jeweilige Datei komplett auswerten konnte. Das wiederum bedeutet, ich kann die Verlinkten Keys erst am Ende der Verarbeitung kennen.

Wenn ich das weiter denke würde es darauf hinauslaufen, dass ich aus den Dateien erst einmal eine Im Memory Datenstruktur bauen müsste, welche ich dann im Nachhinein, nachdem die Stammdaten in der Datenbank abgelegt wurden, mit den richtigen Keys füttere, bevor ich die Transaktionen für die Bewegungsdaten fahren kann.

Da muss ich mal in mich gehen um zu sehen ob mir das Gefällt und ob die Speicherauslastung auf den Clients dadurch nicht zu sehr wächst.

Yup, ich lese die Daten erst in den RAM, stelle alles was geht zusammen, hohle mir dann die Rechte zum Schreiben, mache die letzten Tests die nur gehen wenn ich mir sicher sein kann dass ich als einziges am einfügen bin und jage dann alles in eine Transaktion und sende diese ab. Egal ob es knallt oder nicht gebe ich dann die Rechte wieder ab so dass jemand anderes weiter machen kann.
Ich werte zum Teil einige tausend Datensätze aus und generiere dabei weitere Informationen. Alles landet dabei in MemTables so dass ich mich nicht um die Verwaltung kümmern muss und die Zugriffszeiten passen. Einen wirklichen Anstieg des RAM habe ich dabei nicht bemerkt.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?