Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ineffiziente Implementierung des Verknüpfens einer Sollbuchung bei einem Mitglied mit Buchung #159

Open
lukas-mertens opened this issue Feb 18, 2024 · 17 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@lukas-mertens
Copy link

In unserem Setup läuft die MySQL-Datenbank auf einem Remote-Server und wird per SSH getunnelt. Der Grund: Unsere Vereinswebseite greift über einen View auf Informationen aus JVerein zurück, um Mitgliedern z.B. anzuzeigen, ob sie alle ihre Beiträge bezahlt haben. Dadurch entsteht jedoch ein Problem: Manche Funktionalitäten haben schlechte Performance. Eine Funktion sticht besonders heraus, alle anderen sind akzeptal: Das Verknüpfen eines Mitglieds mit einer Buchung. Das Drücken des entsprechenden Knopfes beim Bearbeiten einer Buchung sorgt dafür dass das Programm für etwa 15 Minuten einfriert, bis sich das entsprechende Popup öffnet.

Grund: Ich hatte vor einer Weile mal debuggt woran das liegen könnte. Damals ist mir aufgefallen dass das Drücken des Knopfes ca. 20.000 Queries an die Datenbank auslöst. Das scheint lokal überhaupt kein Problem zu sein, durch die gesteigerte Round-Trip-Time wenn die DB nicht lokal liegt, führt es aber zu extremen Performance-Problemen.

Vorschlag: Man müsste sich die entsprechende Stelle mal anschauen. Meine Vermutung: Es wurde so implementiert dass in einem Loop ein Query nach dem anderen gemacht wird, um Mitglieder zu suchen o.ä. Vermutlich könnte man das Problem lösen, indem man alle nötigen Queries zuvor zusammenfasst und in einem an die DB schickt und anschließend das Ergebnis interpretiert oder indem man auf eine asynchrone Bearbeitung der einzelnen Queries setzt.

@dippeal
Copy link
Member

dippeal commented Feb 19, 2024

Meinst du in den Buchungen > rechtsklick > Mitgliedskonto zuordnen?

@dippeal dippeal added the enhancement New feature or request label Feb 19, 2024
@lukas-mertens
Copy link
Author

@dippeal ich meine diesen Button
CleanShot 2024-02-19 at 14 38 28

@lukas-mertens
Copy link
Author

@dippeal Hier sieht man was ich meine. Leider ist der Beginn des Spikes nicht drauf, da es zu lange gedauert hat, aber du siehst dass solange das Modal "Mitgliedskonto-Auswahl" geöffnet wird, sind die Queries an die Datenbank extrem erhöht. Du siehst im Graph den Knick zu dem Zeitpunkt als das Öffnen dann endlich abgeschlossen war

CleanShot 2024-02-19 at 14 44 26

@dippeal
Copy link
Member

dippeal commented Feb 19, 2024

Ja. Bin der Meinung es liegt an https://github.com/openjverein/jverein/blob/master/src/de/jost_net/JVerein/gui/control/MitgliedskontoControl.java#L808. Muss man mal schauen ob das in ein SQL statement gepackt werden kann.

@lukas-mertens
Copy link
Author

@dippeal Ich schreibe mal 20 Euro Kopfgeld auf eine effiziente Implementierung aus! :)

@JPT77
Copy link

JPT77 commented Mar 1, 2024

Hehe. Ich habe gerade herausgefunden, dass die Implementierung an sich recht sinnlos ist.
Es wird über ALLE MK gegangen, dabei sollte man nur über sämtliche Mitglieder gehen, und dann nur die MK eines einzigen oder weniger Mitglieder.
Siehe #178

@dippeal
Copy link
Member

dippeal commented Mar 1, 2024

Würde ich so nicht sagen. Die Suchmaske sucht nach Mitgliedern mit dem eingegebenen (Teil-)Namen. Für jedes gefundene Mitglied wird eine Gewichtung durchgeführt (höher gewichtete Ergebnisse werden weiter oben in der Liste aufgeführt). Dann wird für jedes Mitglied die Buchungen gesucht.

@dippeal dippeal added the help wanted Extra attention is needed label Mar 1, 2024
@JohannMaierhofer
Copy link

JohannMaierhofer commented Mar 2, 2024

Der Code prüft auch das Zweck Feld im MK.
Zu diesem Vorgehen stellt sich mir aber die Frage nach dem User Case für den Vergleich mit dem Zweck im MK. Man möchte eine Zahlung (Buchung) die einer gemacht hat einem anderen Mitglied (MK) zuordnen.
Wie ich in den verlinkten Issue geschrieben habe sehe ich dafür den Fall, dass z.B. Eltern die Miete für Kinder bezahlen aber deren Familienname anders lautet. Die Kinder sind die Mitglieder. So einen Fall habe ich bei mir.
Da gibt es bei mir keinen Match und ich bekomme alle offenen MK angezeigt und wähle den passenden aus.
Um die bestehenden Implementierungen zu nutzen müsste ich im Zweck des MK den Namen der Eltern eintragen, dann sollte es zu dem Match kommen.
Das ist aber nicht so toll weil ich die Soll Buchungen (MK) per Abrechungslauf erzeuge und da steht im Zweck des MK dann z.B. Miete März. Das ist bei allen Mietern gleich. Ich möchte da auch nichts anderes sehen. Das ist eben der Zweck der Sollbuchung.
Wie ich das machen würde, ist in der Buchung die die Eltern geleistet haben im Buchungs Zweck den Namen des Kindes einzutragen. Meist haben die Eltern das sowieso schon so gemacht. Dieser Weg ist auch aussagekräftig. Die Zahlung ist für das Kind.
Falls man das unterstützen wollte könnte man es so machen. Wenn ich nun den Mitgliedskonto Zuordnen Dialog öffne sollte also im Suchstring der Name + Zweck aus der Buchung stehen evtl. per Default ohne Zweck und dazu holen per Checkbox. Dann suche Mitglieder welche mit dem Suchstring einen Match haben. Für diese Mitglieder suche offene MK.

Ich denke aber auch, dass das so ein spezieller Fall ist und den Aufwand nicht wert.

@JohannMaierhofer
Copy link

Inzwischen habe ich entdeckt, dass es für mein Szenario oben bereits eine Lösung gibt. Ich habe das Familienbeitrag Feature entdeckt. Das kannte ich bisher nicht.
Ich habe meine Mieter immer als Mitglied geführt obwohl sie eigentlich als Adressen geführt werden sollten. Leider kann man nur Adressen in Mitglieder umwandeln aber nicht umgekehrt.

JohannMaierhofer added a commit to JohannMaierhofer/jverein that referenced this issue Mar 4, 2024
@JohannMaierhofer
Copy link

Jetzt gibt es zwei alternative Lösungen für das Problem. Für eines der beiden müssen wir uns entscheiden.
Siehe #182 und #184

@JohannMaierhofer
Copy link

Die Lösung sollte #184 sein.

@SchachtnerTh
Copy link

Der Code prüft auch das Zweck Feld im MK.
Zu diesem Vorgehen stellt sich mir aber die Frage nach dem User Case für den Vergleich mit dem Zweck im MK. Man möchte eine Zahlung (Buchung) die einer gemacht hat einem anderen Mitglied (MK) zuordnen.

Ich bemerke gerade, dass es sich bei diesem Issue um ein Problem handelt, das ich genau so auch habe. Ich arbeite auch von mehreren Standorten und PCs aus mit den selben Daten und tunnele die MySQL-Verbindung mit SSH. Die Performance-Probleme beim Zuordnen von Buchungen zu Mitgliedskonten, bzw. deren lange Laufzeit empfinde ich auch als sehr störend. Ich möchte deshalb hier gerne mithelfen, wenn ich kann.

Zu dem hier angesprochenen Thema: Ich bin für eine Hilfsorganisation tätig, der Leute Geld spenden können. Das passiert oft durch Überweisungen vom Konto des Spenders, was überhaupt kein Problem darstellt. Aber es kann auch passieren, dass mir bei einer Veranstaltung, bei einem Vortrag oder sonst irgendwo auf der Straße eine Spende mitgegeben wird. Wie kriege ich diese Spende einem Mitgliedskonto zugeordnet?

Ich sehe zwei Möglichkeiten:

  1. Ich zahle sie in die Kasse ein (Konto: Kasse). Da gebe ich als Betreff an: "Spende Michael Meier". Das geht, wenn ich die Kasse bei mir zu Hause habe.

  2. Ich behalte die 50 Euro, die mir gegeben wurde und bringe sie nicht umständlich zum Kassier, sondern überweise am Abend den Betrag von meinem Konto auf das Vertragskonto, ebenfalls mit dem Betreff: "Spende Michael Meier".

In beiden Fällen wäre es gut, wenn bei der Zuordnung der Spende zu einem Mitgliedskonto nicht nur mein Mitgliedskonto auszuwählen wäre, sondern wenn auch der Name aus dem Betreff für die Suche des Spenders verwendet werden könnte.

Wenn ich das richtig verstehe, geht es genau um diese Funktion, die ggf. entfernt werden soll, oder? Ich nutze das Feature schon regelmäßig. Vielleicht gibt es dafür aber auch eine andere Vorgehensweise. Ich finde mein Vorgehen aber ziemlich einfach und erspare es mir, jedes Mal extra zum Kassier fahren zu müssen. Besonders bei kleineren Spenden ist das was, das man vielleicht schiebt und mehrere Spenden zusammenkommen lässt oder dann irgendwann vielleicht sogar mal vergessen könnte...

LG Tom

@JohannMaierhofer
Copy link

Hallo @SchachtnerTh ,
ich habe das oben schon ausführlicher beschrieben. Deinen Anwendungsfall verstehe ich.
Die momentane Implementierung die ich gestrichen habe ist aber nicht für deinen Fall geeignet. Wie beschrieben vergleicht der alte Code ob ein Teilstring aus dem Namen der Buchung im Zweck der Sollbuchung enthalten ist. Dahinter sehe ich keinen Anwendungsfall.
Für deinen Anwendungsfall müsste geschaut werden ob im Zweck der Buchung ein Name vorkommt.
Auch ist die aktuelle Implementierung für den Fall, dass eine Sollbuchung existiert, also für den ersten Tab im Sollbuchnug Auswahldialog.
In deinem Fall hast du ja keine Sollbuchung und suchst nach einem Namen im zweiten Tab der eine neue Sollbuchung erzeugt und die Istbuchung zuordnet. Da war nie ein Vergleich mit dem Zweck implementiert. Da verstehe ich auch nicht wie du das dann schon benutzen konntest?

Der Weg für deinen Fall wäre, im zweiten Tab einfach deinen Namen zu löschen und Suchen wählen. Dann werden alle Namen angezeigt und du wählst dann den richtigen aus, also den "Michael Meier" in deinem Fall. Dann wird die Spende richtig zugeordnet.

Man könnte aber das gewünschte Feature für diesen Fall implementieren. Allerdings wird dann die Suche deutlich langsamer weil dann jedes Wort aus dem Zweck der Buchung mit den Vornamen und Nachnamen verglichen wird. Da die Suche hier aber nur über die Mitglieder geht und nicht über alle Sollbuchungen (wie im ersten Tab) sollte das aber trotzdem ok sein.

Wenn man das aber selten braucht ist wohl eher der Weg über das Löschen des Namens einfacher.

@SchachtnerTh
Copy link

Hast schon recht. Ich hab das gestern noch gar nicht so ganz verstanden, glaub ich.
Es kann schon sein, dass ich da wirklich den Namen bei der Suche rausgelöscht hab und das Mitglied dann aus der kompletten Mitgliederliste rausgelöscht habe. Sry für die Verwirrung.
Ich kann nicht beurteilen, ob das vielleicht irgendwer brauchen könnte. Wir brauchen es auf jeden Fall sicherlich nicht. 👍

@stefanheinrichsen
Copy link

Bei mir ist diese Textbox in der Mitgliederzuordnung fast nicht zu verwenden weil sie sehr träge reagiert. Ich vermute, dass dort mit jeder Zeichenänderung neue Abfragen erzeugt werden um die Ergebnisse unten anzuzeigen. Das Problem sollte sich dann mit dem Fix #184 auch erldigt haben, oder?

@JohannMaierhofer
Copy link

Ja, das war ein Problem und zwar nicht nur in diesem Dialog sondern auch in allen Views mit Suchfiltern. Es wurde beim editieren von Text- und Datumsfeldern bei jedem Buchstaben/Ziffer oder Klick ein Query ausgelöst ohne aber gleich die Anzeige zu ändern.
Dieses habe ich mit #196 korrigiert. Jetzt wird beim Editieren von Eingabefeldern kein Query mehr gemacht sondern erst beim Drücken des Suchen Buttons oder mit Return.
PS: Der Dialog hat jetzt auch den Suchen Button.

@willuhn
Copy link
Member

willuhn commented Apr 15, 2024

Es wurde beim editieren von Text- und Datumsfeldern bei jedem Buchstaben/Ziffer oder Klick ein Query ausgelöst ohne aber gleich die Anzeige zu ändern. Dieses habe ich mit #196 korrigiert. Jetzt wird beim Editieren von Eingabefeldern kein Query mehr gemacht sondern erst beim Drücken des Suchen Buttons oder mit Return.

Wenn man dennoch möchte, dass direkt nach Eingabe von Text eine Aktion ausgeführt werden (egal ob eine Suche oder etwas anderes), ohne dass dafür noch separat ein Button gedrückt werden soll, dann bietet sich hier alternativ auch der "DelayedListener" von Jameica an.

Mit dem ist es möglich, mehrere schnell aufeinanderfolgende Events (z.B. beim Tippen nach jedem Zeichen) zu bündeln und das Event erst dann auszulösen, wenn innerhalb einer bestimmten Zeit (meist zwischen 500 und 1000ms) keine weiteren Zeichen mehr getippt wurden. Damit kann man den Text in Ruhe zu Ende tippen und die Suche startet erst, wenn man fertig ist.

Verwendet wird der DelayedListener einfach als Wrapper. Man erzeugt einen DelayedListener und übergibt im Konstruktor den eigentlichen Listener sowie optional das Timeout. Diesen DelayedListener hängt man dann an das Text-Eingabefeld. Der eigene Listener wird dann erst aufgerufen, wenn innerhalb der definierten Anzahl von Millisekunden keine weiteren Zeichen mehr eingegeben wurden.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

7 participants