Datentypen Map effizient mit eigenem Key

Noch mal zum Thema immutable Keys... Die Keys sollen ja die DB-Abfragen beinhalten. Andere DB-Abfragen haben andere Resultate zur Folge. Ferner folgt daraus, dass veränderte DB-Abfragen nebst ihren Resultaten ohnehin neu in den Cache aufgenommen werden müssen. Das einzige, was sich an dem Schlüssel ändert wäre der Usecount bzw. der Zeitpunkt, an dem die Abfrage zum letzten mal stattfand. Diese Werte sind aber weder für "equals()" und "hashCode() noch für "compareTo()" relevant und können dort ignoriert werden. Den Rest der Schlüsselklasse kann man deswegen immutable gestalten, das ist definitiv um einiges performanter, weil das ständige Rehashing entfällt. "hashCode()" selbst könnte man dann z.B. mit 32-Bit RSA oder CRC32 per Objektserialisierung implementieren, der Hashcode wäre ja dann final.
BTW: Betrifft den oben genannten Begriff Usecount...
Als gute Idee hat sich bereits folgendes ergeben. Die Abfrage erhält bei ihrer ersten Verwendung einen Zeitstempel und einen Usecount von 1. bei jeder erneuten Verwendung inkrementiert man den Usecount. Mit einer Formel wie [c]currentTime - timeStamp <= useCount * minTimeToCache[/c] kann man so aufgrund der Häufigkeit der Verwendung entscheiden, wann die Abfrage aus dem Cache entfernt werden soll. Höhere UseCounts bedeuten längere Cache-Zeiten. Natürlich kann man die Formel auch so umstellen, dass man den Zeitstempel lediglich um minTimeToCache pro Verwendung erhöhen kann.
 
Noch mal zum Thema immutable Keys... Die Keys sollen ja die DB-Abfragen beinhalten. Andere DB-Abfragen haben andere Resultate zur Folge. Ferner folgt daraus, dass veränderte DB-Abfragen nebst ihren Resultaten ohnehin neu in den Cache aufgenommen werden müssen. Das einzige, was sich an dem Schlüssel ändert wäre der Usecount bzw. der Zeitpunkt, an dem die Abfrage zum letzten mal stattfand. Diese Werte sind aber weder für "equals()" und "hashCode() noch für "compareTo()" relevant und können dort ignoriert werden. Den Rest der Schlüsselklasse kann man deswegen immutable gestalten, das ist definitiv um einiges performanter, weil das ständige Rehashing entfällt. "hashCode()" selbst könnte man dann z.B. mit 32-Bit RSA oder CRC32 per Objektserialisierung implementieren, der Hashcode wäre ja dann final.
BTW: Betrifft den oben genannten Begriff Usecount...
Als gute Idee hat sich bereits folgendes ergeben. Die Abfrage erhält bei ihrer ersten Verwendung einen Zeitstempel und einen Usecount von 1. bei jeder erneuten Verwendung inkrementiert man den Usecount. Mit einer Formel wie [c]currentTime - timeStamp <= useCount * minTimeToCache[/c] kann man so aufgrund der Häufigkeit der Verwendung entscheiden, wann die Abfrage aus dem Cache entfernt werden soll. Höhere UseCounts bedeuten längere Cache-Zeiten. Natürlich kann man die Formel auch so umstellen, dass man den Zeitstempel lediglich um minTimeToCache pro Verwendung erhöhen kann.

Das mit den final Feldern ist eine gute Idee und wird gleich mal getestet 😉
 
Also ich kann dir sagen warum die DB bei dir so lahmt: Dein DB Manager ist Müll. Du machst ja bei jedem Update/Insert/irgendwas ein System.out.println. Das bremst SO enorm, wenn du das bei deinem HashTable auch machen würdest, lägst du in der gleichen zZ
 
Also ich kann dir sagen warum die DB bei dir so lahmt: Dein DB Manager ist Müll. Du machst ja bei jedem Update/Insert/irgendwas ein System.out.println. Das bremst SO enorm, wenn du das bei deinem HashTable auch machen würdest, lägst du in der gleichen zZ

Nimm die Ausgabe raus,
oder pack sie bei der HashMap rein,
am besten beides mal ausprobieren ...
dann siehst du, dass dies ein unwichtiger Faktor ist 😉

Das Netzwerk ist einfach der Flaschenhals,
selbst lokal, ein L2 Cache, wie der RAM ist einfach
schneller, alleine weil er näher am Prozessor ist ...
 
Aber es ist einfach nicht sinnvoll sich über Performance und Caching gedanken zu machen, wenn der Code des DB Controllers dermaßen ineffizient ist. Und ich muss dir hier ja nichts beweisen, du bist der mit dem Performaceproblem
 
Ich kann dir sagen was du falsch machst:
  • Du bastelst bei jeder Abfrage einen neuen String zusammen.
  • Du schliesst deine Statements nicht.
  • Du erledigst alles über eine einzelne Connection.
  • Du machst mehrere System.out.printlns bei jeder Abfrage.
Nochdazu ist deine Konstruktion etwas unübersichtlich zu durchblicken. Normalerweise hat man z.B für ein Insert in eine Tabelle eine Funktion, in der steht der nicht veränderbare sql String fürs Prepared Statement z.B "INSERT INTO emp (vorname,nachname) VALUES(?,?)". Ohne zusammenbauen und ohne weiterreichen in irgendeine fastInsert Funktion.
 
Kurze Frage, kurze Antwort 😉

Wenn Du viele Key-Objekte erzeugst und das vermeiden willst, bist Du mit einem Pool sehr gut bedient. Zur Vereinfachung kannst Du Dir zusätzlich noch Factory-Klassen/Methoden schreiben, die die Keys zurückgeben, fertig.
 
Naja wahrscheinlich Reduzierung von Objekterzeugungen oder nicht? Es macht schon einen Unterschied, ob ich für (1,2,3, "a") jeweils n- XXXKey's erzeuge, oder nur einmal, und das Teil dann poole/share.
 
Ich kann dir sagen was du falsch machst:
  • Du bastelst bei jeder Abfrage einen neuen String zusammen.
  • Du schliesst deine Statements nicht.
  • Du erledigst alles über eine einzelne Connection.
  • Du machst mehrere System.out.printlns bei jeder Abfrage.
Nochdazu ist deine Konstruktion etwas unübersichtlich zu durchblicken. Normalerweise hat man z.B für ein Insert in eine Tabelle eine Funktion, in der steht der nicht veränderbare sql String fürs Prepared Statement z.B "INSERT INTO emp (vorname,nachname) VALUES(?,?)". Ohne zusammenbauen und ohne weiterreichen in irgendeine fastInsert Funktion.


1. Hast du Recht, aber aus irgendeinen Grund optimiert das JAVA weg ...
zumindes bei mir^^
Ist ja auch eine Quick und Dirty Klasse, sonst arbeite ich immer mit PreparedStatments ...
2. Mist, da hast du Recht xD
3. Willst du für jede Abfrage eine eigene Connection machen? Wie sollte man es denn machen?
4. Hatte die auch mal rausgenommen, ändert nichts, hatte ich aber schon geschrieben ...

Naja wahrscheinlich Reduzierung von Objekterzeugungen oder nicht? Es macht schon einen Unterschied, ob ich für (1,2,3, "a") jeweils n- XXXKey's erzeuge, oder nur einmal, und das Teil dann poole/share.

Korrekt^^
So hätte ich es dann auch bei den Connections gemacht ...
 
1. Hast du Recht, aber aus irgendeinen Grund optimiert das JAVA weg ...
zumindes bei mir^^

Glück gehabt bis jetzt...

Ist ja auch eine Quick und Dirty Klasse, sonst arbeite ich immer mit PreparedStatments ...

quick and dirty ist, was es ist. Dann mach das, was Du auch sonst immer machst.

2. Mist, da hast du Recht xD
3. Willst du für jede Abfrage eine eigene Connection machen? Wie sollte man es denn machen?

Wenn es stört, dann benutze einfach mehrere Connections. Die mußt Du dann aber auch verwalten, d.h.Öffnen/Schliessen etc. ConnectionPool vielleicht?
 
Naja wahrscheinlich Reduzierung von Objekterzeugungen oder nicht? Es macht schon einen Unterschied, ob ich für (1,2,3, "a") jeweils n- XXXKey's erzeuge, oder nur einmal, und das Teil dann poole/share.

Soso, mal angenommen der Benutzer gibt dir ein Key 1,2,3. Dann bist du so schlau und speicherst jetzt 123 in deinen KeyPool. Jetzt kommt von irgendwoher noch eine Anfrage nach dem Wert für den Key 123. Jetzt schaust du also im Keypool nach, ob 123 drin ist und holst den string da raus oder wie? Oder meinst du gleich das Caching das dragonfire mit seiner Hashmap ja erreichen will.
Leider füllt sich deine Hashmap irgendwann und ist dann genausogroß wie die Datenbank. Das heisst dann brauchst einen Mechanismus, der die gecachten Daten wieder vergisst.
Warum nicht gleich alles einlesen?
Wenn nach der Optimierung bei der DB Anbindung wirklich noch Bedarf an mehr Performance ist, kann man ja auf Caching zurückgreifen. Ich hab glaub ich einen Link zu so einem Projekt gepostet, bei dem ich zumindest denke dass sich die Entwickler mehr Überlegungen und Wissen hineingesteckt haben, als du oder ich hier. Du benutzt schließlich auch die vorgefertigte Hashmap und keine selbst zusammengehackte.

Zu 1. Nein, Java optimiert das nicht weg. Konnte ich selbst bei einer Anwendung mit ein paar Millionen Inserts erfahren, wo die Laufzeit unter anderem durch effizientens Erstellen von SQL Code von 45 Minuten auf 2 reduziert wurde.
3. Google mal ConnectionPool. Besonders wenn du, wie hier angedeutet, viele Parallele Zugriffe auf deinen Server und deine Db hast, ist eine größtmögliche Parallelisierung des DB Zugriffs natürlich enorm wichtig. Datenbanken sind ja auf Mehrbenutzerbetrieb ausgerichtet.
 
Zuletzt bearbeitet:
Soso, mal angenommen der Benutzer gibt dir ein Key 1,2,3. Dann bist du so schlau und speicherst jetzt 123 in deinen KeyPool. Jetzt kommt von irgendwoher noch eine Anfrage nach dem Wert für den Key 123. Jetzt schaust du also im Keypool nach, ob 123 drin ist und holst den string da raus oder wie?
warum nicht?

Leider füllt sich deine Hashmap irgendwann und ist dann genausogroß wie die Datenbank. Das heisst dann brauchst einen Mechanismus, der die gecachten Daten wieder vergisst.

Den brauchst er sowieso, um seinen Cache aktuell zu halten.

Warum nicht gleich alles einlesen?

Die ganze DB einlesen? Weis nicht... Außerdem hat er beschrieben, daß er nicht nur DB's als Datenquellen hat.

Ich hab glaub ich einen Link zu so einem Projekt gepostet, bei dem ich zumindest denke dass sich die Entwickler mehr Überlegungen und Wissen hineingesteckt haben, als du oder ich hier. Du benutzt schließlich auch die vorgefertigte Hashmap und keine selbst zusammengehackte.

Das überzeugt mich jetzt irgendwie nicht so... Er hat halt eine Lösung genommen, die für ihn 100% passt, was garantiert bei vielen Fertiglösungen nicht so sein wird.
 
Was bringt dir der Pool? Du hältst dann alle bereits verwendeten Keys in einer Collection. Die neuen Keys die reinkommen sind aber wieder seperate Objekte, also speicherst du dadurch alles doppelt.
Das ist so als hättest du ein Telefonbuch - deine DB - und ein Buch, in dem alle Namen nochmal drinstehen - deinen Keypool. Wenn du jetzt die Telefonnummer von Max Mustermann suchst, siehst du erst in deinem Namensbuch nach ob er da drinsteht und dann im Telefonbuch??? Das ist doch unsinn!
Und nein, diesen Mechanismus hat er eben nicht, zumindest nicht gepostet.
 
Zuletzt bearbeitet:
Hier stimme ich bERt0r definitiv zu. Die Keys des Cache wären die Statements, die Values halt die Resultate. Die Statements sind in einer Anwendung aber meistens recht zahlreich und obendrein auch noch verschieden. Sie deswegen zusätzlich noch in einem Pool zu halten macht wirklich absolut keinen Sinn. Aber für den Fall, es wird doch einer benötigt...
Java:
Set<Key> pool = MyMap.keySet();
bitteschön... 😉
 
Statements zu speichern bringt in diesem Fall aber nicht viel, da verschiedenste Datenquellen angebunden werden sollen (auch nicht SQL).
 
Ich habe mich jetzt einfach für die HashMap entschieden und ohne KeyPool,
mit dem einem new muss ich halt leben^^
Das verwalten der Keys ist ein wenig "überdimensioniert" und wie beschrieben wurde,
erst nachzuschauen was der Key ist um dann in der Map den Wert zu finden ....
dazu passt die Anwendung nicht ...
Hatte mal für jeden Thread einen eigenen "SuchKey" bereitgestellt,
die Performancesteigerung war gleich null, JAVA kann sowas anscheinende echt gut xD

Das Telefonbuch-Beispiel passt hier ganz gut ...

Ich habe immer wieder die gleichen Anfragen nach Nummern aus einer GROSSEN Menge,
also bastel ich mir ein kleines eigenes Telefonbuch,
wo das nachschauen schneller geht.

Wenn ich es dort nicht finde,
schaue ich im großen Telefonbuch nach oder rufe die Auskunft an xD

PS.: Kennt sich einer zufällig mit JAVA Persistence aus?
 

Zurück
Oben