Tabelle sequentiell bzw unique lesen

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
charlytango
Beiträge: 843
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Tabelle sequentiell bzw unique lesen

Beitrag von charlytango »

Hi,

    Daten in einer MySQL Tabelle sollen abgearbeitet werden sollen.
    Die Reihenfolge der Bearbeitung muss nicht zwingend einer bestimmten Reihung folgen -- gelegentlich kann das aber auch nötig sein.
    Damit das schneller erfolgt sollen mehrere PCs/Programminstanzen/Clients daran arbeiten.
    Jeder Datensatz soll nur einmal bearbeitet werden.
    Das ganze soll auch performant sein
    edit: Clients sollen nach Bedarf zugeschaltet oder abgeschaltet werden können

Nun gibt es dazu die Möglichkeit einer Semaphordatei, die gesperrt wird solange die Abfrage eines Programms dauert. Die muss aber auf einem Netzwerklaufwerk liegen, was die Sache unelegant macht.

bisher habe ich folgende Strategie angewandt:
    Abfragen der nächsten 20 unbearbeiteten Datensätze
    zufälliges Auswählen eines Datensatzes aus den 20
    Versuch den ausgewählten Datensatz auf Rowlevel zu sperren
    falls das nicht klappt alles von vorne.

Das hat in der Vergangenheit ganz gut geklappt, allerdings kam es immer wie der zu Lockingproblemen und Timingproblemen.
Die (recht große) DB konnte nicht schnell genug 'liefern' was die Clients ins Timeout geschickt hat.

Frage:
Gibt es eine elegantere Lösung? z.B. eine Variante wie SELECT LAST_INSERT_ID() bei autoincrement Feldern ?
Trigger?
Stored Procedure?

Danke im voraus
Zuletzt geändert von charlytango am Di 31. Okt 2017, 10:08, insgesamt 1-mal geändert.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Tabelle sequentiell bzw unique lesen

Beitrag von m.fuchs »

Wenn ich dein Problem richtig verstehe, würde ich es darüber lösen dass jeder Client nur einen bestimmten Bereich der Tabelle bearbeitet. Dann kommen die sich auch nicht ins Gehege und du musst nicht einzelne Datensätze sperren.
Bei zwei Clients zu Beispiel einer Datensätze mit ungerader, der andere gerader ID.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

charlytango
Beiträge: 843
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Re: Tabelle sequentiell bzw unique lesen

Beitrag von charlytango »

m.fuchs hat geschrieben:Bei zwei Clients zu Beispiel einer Datensätze mit ungerader, der andere gerader ID.


Danke, das bringt mich darauf dass ich die Angabe verbockt habe:
Clients sollen dynamisch zugeschaltet oder stillgelegt werden können ohne dass die Verteilung der Daten leidet.
Ich weiß vor dem Job also nicht wieviele Clients daran arbeiten werden und das ist über die Joblaufzeit auch nicht konstant.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Tabelle sequentiell bzw unique lesen

Beitrag von m.fuchs »

Auch das wäre recht ähnlich möglich. Du unterteilst die Tabelle in Gruppen mit Datensätzen eines ID-Bereichs. (Beispiel: 1-100, 101-200, 201-300)

Jeder Client holt sich einen Bereich und sperrt diesen als in Bearbeitung. Wenn er fertig ist, markiert er den Bereich als fertig und sucht sich den nächsten freien. Du sperrst also nicht immer einen Datensatz sondern gleich 100.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Tabelle sequentiell bzw unique lesen

Beitrag von Socke »

Nutzt du die Sperrung durch SELECT .. FOR UPDATE?

Du könntest neben der Datenbank einen eigenen Server zur Lastverteilung einrichten (gibt immer die ID des als nächsten zu bearbeitenden Datensatzes zurück); dieser muss dann natürlich neben der Datenbank laufen, damit die Clients arbeiten können.
Alternativ können die Daten auch auf Anwendungsebene durch ein entsprechendes Kennzeichen in der Datenbank gesperrt werden (ohne SELECT .. FOR UPDATE); die Sperrinformationen können dan aus Gründen der Performance in eine separate Tabelle ausgelagert werden.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

charlytango
Beiträge: 843
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Re: Tabelle sequentiell bzw unique lesen

Beitrag von charlytango »

Ein eigener Server oder Serverprozess als Lastverteiler wäre eher unpraktisch im gewünschten Szenario

ganz habe ich das trotzdem nicht verstanden...

könnte ich also mit

Code: Alles auswählen

SELECT top 1 WHERE.. FOR UPDATE
den einen Datensatz sperren der quasi der nächste ist ?
Wird dabei auch verhindert dass ihn gleichzeitig ein anderer Client anfordert?
Meine Gedanken kreisen weniger um das Blocken eines Datensatzes für andere. Das habe ich bislang mit drei Timestamps gemacht: Locked, InProgress, Ready

Damit kann ich auch Jobs identifizieren die während der Bearbeitung schief gegangen sind.

Ich mache mir eher Sorgen das zwei Clients die gleichen Daten versuchen zu sperren. Wie wird das von MySQL aufgelöst?

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Tabelle sequentiell bzw unique lesen

Beitrag von Socke »

charlytango hat geschrieben:könnte ich also mit

Code: Alles auswählen

SELECT top 1 WHERE.. FOR UPDATE
den einen Datensatz sperren der quasi der nächste ist ?
Wird dabei auch verhindert dass ihn gleichzeitig ein anderer Client anfordert?
Meine Gedanken kreisen weniger um das Blocken eines Datensatzes für andere. Das habe ich bislang mit drei Timestamps gemacht: Locked, InProgress, Ready

Damit kann ich auch Jobs identifizieren die während der Bearbeitung schief gegangen sind.

Ich mache mir eher Sorgen das zwei Clients die gleichen Daten versuchen zu sperren. Wie wird das von MySQL aufgelöst?

Da du bisher nichts von den Feldern geschrieben hattest, war ich mir unsicher, wie du die Sperren umsetzt. Was ist denn das Problem mit deinen Sperr-Feldern? Wenn die Aktualisierung der Sperrinformationen zu lange dauert (timeout), dann lager diese in eine eigene Tabelle aus (die dann optimaler Weise vollständige im Cache gehalten werden kann).

SELECT ... FOR UPDATE sperrt alle selektierten Datensätze bis zum Ende der Transaktion. Beendet ein Client die Verbindung (COMMIT oder ROLLBACK), werden die Sperren freigegeben und ein anderer Client kann die Datensätze sperren.
Solltest du mehrere Tabellen damit sperren, müssen diese immer in der gleichen Reihenfolge (1. Tabelle A, 2. Tabelle B usw.) in der gesamten Anwendung gesperrt werden um Deadlocks zu vermeiden.
Ein anderer Client kann den selben Datensatz gleichzeitig anfordern, muss dann aber warten bis der erste Client fertig ist. Die Auswahl des Datensatzes muss also wie bisher über die WHERE-Bedingung erfolgen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten