2016-07-22 8 views
4

Ich versuche, etwa 5 Millionen Objekte geladen von DB über Hibernate in eine Hash-Karte zu laden. Ich mache das für 2 Arten von Klassen (A & B). Ich wiederhole die Pojos. Der Schlüssel ist ein Feld aus dem Pojo und der Wert ist das Pojo selbst.

1. Für den Klasse-A-Typ ist der Schlüssel ein Integer-Feld. Ich kann die Karte in weniger als 20 Sekunden laden.

Für Klasse B
2.a) Test 1, mein Schlüssel ist ein String-Feld. Wenn ich versuche, diese Objekte in eine neue hashmap zu laden (erneuter Versuch durch Neustart des Java-Prozesses, also noch keine Bedenken von GC), dauert es etwa 30 Sekunden, um 100K-Objekte in die Karte zu laden.
2.b) Test 2, wenn ich versuche, ein anderes Feld aus dieser Klasse (Integer-Typ) zu verwenden und die Karte zu laden, funktioniert es wie die erste und lädt in weniger als 20 Sekunden.
2.c) Test 3, fragte ich mich, ob das Problem der Datentyp war. Also habe ich für Klasse B einen anderen Ansatz zum Erstellen eines Zeichenfolgenschlüssels unter Verwendung des Ganzzahlfeldes in # 2.b versucht. (key = int_field + "") und es in < 20 Sekunden geladen.Hashmap Put-Leistung variiert basierend auf Schlüsseln

Ein anderer Test, Test 4, den ich für Klasse B gemacht habe, war die Art, wie ich den Schlüssel erstellt habe. Für 2.c habe ich den Schlüssel wie folgt erstellt:
map.put (pojo.getIntField() + "", pojo);
Ergebnis war, wie oben erwähnt in 2.c

2.d) Aber wenn ich erstellt einen anderen Getter in der pojo die int_field + "" und verwendet diese in der Karte als
setzen zurück map.put (pojo.getIntFieldInStringForm(), pojo);
Die Leistung verschlechterte sich bei 100K-Objekten auf etwa 30 Sekunden.

Ich weiß, dass das Problem mit den Schlüsseln ist, weil ich die db fetch-Phase verifiziert habe, indem ich die Ergebnisobjekte zu einer Liste hinzugefügt habe und sie in < 20 Sekunden für beide Typen lädt.

Ich bin nicht in der Lage, den Grund dafür zu verstehen. Wenn irgendjemand das Licht dazu bringen könnte, wäre das sehr hilfreich. Sehr geschätzt.

Dank

Editiert: Code Hinzufügen Schnipsel hier (Verzeihen Sie die Formatierung/Tippfehler falls vorhanden):
Test auf # 1

Map<String, ClassA> map = new HashMap<String, ClassA>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassA> iterator = session.createQuery("from ClassA").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassA = iterator.next(); 
     map.put(objClassB.getIntField(), objClassA);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 


-Test für # 2.a

Map<String, ClassB> map = new HashMap<String, ClassB>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassB> iterator = session.createQuery("from ClassB").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassB = iterator.next(); 
     map.put(objClassB.getStringField(), objClassB);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 


Test für # 2.b


-Test für # 2.c

Map<String, ClassB> map = new HashMap<String, ClassB>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassB> iterator = session.createQuery("from ClassB").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassB = iterator.next(); 
     map.put(objClassB.getIntField() + "", objClassB);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 


-Test für # 2.d

Map<String, ClassB> map = new HashMap<String, ClassB>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassB> iterator = session.createQuery("from ClassB").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassB = iterator.next(); 
     map.put(objClassB.getIntFieldInStringForm() + "", objClassB);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 
+0

Mit 'string + string' erstellen Sie einen neuen' StringBuilder', wenn Sie die concat-Operation noch nicht verarbeiten, was die Performance beeinträchtigen könnte, wenn Sie es innerhalb einer Schleife tun. Verwenden Sie stattdessen "Integer.toString (int)". Nur ein Hinweis. Weiter: Wie groß sind die 'String' Objekte, die Sie von der db laden? –

+0

Warum würden Sie '+ '" 'nach' getIntFieldInStringForm() 'tun, wenn der Wert bereits ein String ist? --- Wenn die Leistung für Sie kritisch ist, ersetzen Sie 'getIntField() + '" 'durch' Integer.toString (getIntField()) '. --- In 2a, wie groß sind die Strings? – Andreas

+0

Wir können nicht sehen, was Sie in Ihren Testfällen tun. Erstellen Sie einen kleinen Testfall, der dieses Problem reproduziert. Oder wie im formell nahen Grund: Fragen, die Debugging-Hilfe suchen ("Warum funktioniert dieser Code nicht?") Müssen das gewünschte Verhalten, ein spezifisches Problem oder einen Fehler und den kürzesten Code enthalten, der nötig ist, um es in der Frage selbst zu reproduzieren. Fragen ohne eine klare Problemstellung sind für andere Leser nicht nützlich. Siehe: Erstellen eines minimalen, vollständigen und überprüfbaren Beispiels. –

Antwort

1

Um Elemente in einer HashMap zu setzen, die hashCode der wichtigsten Bedürfnisse zu sein berechnet.Wenn Ihre Strings 8 - 10 Zeichen lang sind, müssen einige Berechnungen durchgeführt werden, um sie auf 32-Bit-Hashcodes abzubilden. Wie groß sind Ihre Integer-Schlüssel? Wenn sie kleiner als 100.000 sind, gibt es nur 5 Zeichen, von denen der HashCode berechnet wird, also ist das ein bisschen schneller.

Sie haben auch einen Leistungseinbruch, wenn zwei Schlüssel den gleichen Hashcode berechnen, was ein paar Mal mit Ihren String-Schlüsseln passieren könnte.

Wenn Sie eindeutige Ganzzahlen als Schlüssel verwenden, werden keine Hash-Kollisionen auftreten. Und vielleicht, wenn Sie Strings verwenden, die Integer konvertiert werden, hat der String-Hash-Algorithmus auch weniger Kollisionen.

+0

Meine ganzzahligen Schlüssel sind 8 Ziffern lang. Was immer noch verwirrend ist, ist der Leistungsunterschied, den ich zwischen 2.c und 2.d sehe. Die String-Schlüssel, die ich hier verwende, sind im Grunde Zahlen im String-Format. Also habe ich versucht, sie in Ganzzahl zu konvertieren und versuchte (etwa 8 Ziffern jetzt) ​​und dies dauerte auch etwa 30 Sekunden für 100K Datensätze. – KNP

+0

Abhängig von der Anfangskapazität und dem Ladefaktor der HashMap können Kollisionen bei Integerschlüsseln auftreten. Da @ nanda-kumar 5M-Elemente in die Karte lädt und keine Anfangskapazität angibt, wird die Karte viel aufgeräumt. – TreeRex

+0

Nur um einen weiteren Punkt hinzuzufügen, während wir über den Ladefaktor sprechen, habe ich einige Tests mit einer Anfangskapazität von 5M und einem Ladefaktor von 1,0 durchgeführt.Betrachtet man etwa 500 doppelte Schlüssel (nicht Hashcode) insgesamt, sah ich nicht viel Verbesserung in der Leistung. Die Geschwindigkeiten kamen um ein paar Sekunden weniger von 30 für 100K Aufzeichnungen herunter, die nirgendwo nah an der Zahl ist, die ich für Test # 1 sehe. – KNP

Verwandte Themen