Ich arbeite an einem J2EE-Projekt, bei dem Postleitzahlen, Städte und Länder zusammen gespeichert werden. Wir haben eine Java-Klasse entwickelt, die die Integration jeder Länderdatei (mit jeder Postleitzahl und jeder Stadt) übernimmt. Das Problem ist, dass für einige Länder (Großbritannien, Niederlande ...) die Datei ziemlich konsequent ist (400.000 bis 800.000 Zeilen).Java - Läuft eine Schleife jedes Mal länger?
Ich habe eine while()
Schleife, die die nächste Zeile liest, erhält die Informationen und speichert sie in meiner Datenbank. Das Problem ist, dass für die 1000 oder 10.000 ersten Zeilen der Prozess schnell ist, sehr schnell, dann scheint es jedes Mal langsamer zu werden, wenn es durch die Schleife geht, dann passiert ein HeapSpaceOverflowException
nach 150.000 Zeilen.
Ich dachte zuerst, dass ein Objekt nicht Müll gesammelt und verlangsamt meinen Algorithmus, aber ich kann nicht herausfinden, welche. Außerdem, wenn ich diesen Algorithmus auf meinem PC, JConsole sagt mir, dass Heap-Speicher wird regelmäßig gereinigt (scheint Müll gesammelt werden), aber der Prozess ist immer langsamer und langsamer ...
Unten ist der Code der Methode :
Variable this.pc
wird durch @Inject Annotation injiziert.
Kann mir jemand helfen herauszufinden, warum dieser Code immer langsamer wird?
Vielen Dank.
Edit: Zur Vervollständigung willen, habe ich den Code der get...()
Methode hinzugefügt:
public Codepostalville getByCodePostalAndVilleAndINSEE(String codePostal, String ville,
String pays, String codeINSEE) throws DatabaseException
{
Codepostal cp = null; Ville v = null; PPays p = null; Codepostalville cpv = null;
try
{
// Tout d'abord, il faut retrouver l'objet CodePostal
cp = (Codepostal) this.em
.createNamedQuery("Codepostal.findByCodePostal")
.setParameter("codePostal", codePostal)
.getSingleResult();
}
catch (NoResultException nre1)
{
// Si on ne l'a pas trouvé, on le crée
if (cp == null)
{
cp = new Codepostal();
cp.setCodePostal(codePostal);
cpc.getFacade().create(cp);
}
}
// On retrouve la ville...
try
{
// Le nom de la ville passé par l'utilisateur doit être purgé (enlever
// les éventuels tirets, caractères spéciaux...)
// On crée donc un nouvel objet Ville, auquel on affecte le nom à purger
// On effectue la purge, et on récupère le nom purgé
Ville purge = new Ville();
purge.setNomVille(ville);
purge.purgerNomVille();
ville = purge.getNomVille();
v = (Ville) this.em
.createNamedQuery("Ville.findByNomVille")
.setParameter("nomVille", ville)
.getSingleResult();
}
catch (NoResultException nre2)
{
// ... ou on la crée si elle n'existe pas
if (v == null)
{
v = new Ville();
v.setNomVille(ville);
vc.getFacade().create(v);
}
}
// On retrouve le pays
try
{
p = (PPays) this.em
.createNamedQuery("PPays.findByNomPays")
.setParameter("nomPays", pays)
.getSingleResult();
}
catch (NoResultException nre2)
{
// ... ou on la crée si elle n'existe pas
if (p == null)
{
p = new PPays();
p.setNomPays(pays);
pc.getFacade().create(p);
}
}
// Et on retrouve l'objet CodePostalVille
try
{
cpv = (Codepostalville) this.em
.createNamedQuery("Codepostalville.findByIdVilleAndIdCodePostalAndIdPays")
.setParameter("idVille", v)
.setParameter("idCodePostal", cp)
.setParameter("idPays", p)
.getSingleResult();
// Si on a trouvé l'objet CodePostalVille, on met à jour son code INSEE
cpv.setCodeINSEE(codeINSEE);
this.getFacade().edit(cpv);
}
catch (NoResultException nre3)
{
if (cpv == null)
{
cpv = new Codepostalville();
cpv.setIdCodePostal(cp);
cpv.setIdVille(v);
cpv.setCodeINSEE(codeINSEE);
cpv.setIdPays(p);
this.getFacade().create(cpv);
}
}
return cpv;
}
Nochmals vielen Dank.
Edit 2: Also, ich habe ein paar mehr Informationen. Die Methode getCodePostal...()
benötigt ungefähr 15 ms, um am Anfang der Schleife ausgeführt zu werden, und nach 10.000 Zeilen benötigt sie mehr als 100 ms, um ausgeführt zu werden (fast 10 mal mehr!). In dieser neuen Version habe ich den Commit/Rollback-Code deaktiviert, so dass jede Abfrage sofort ausgeführt wird.
Ich kann nicht wirklich finden, warum es mehr und mehr Zeit braucht.
Ich habe einige Informationen über JPA-Cache zu suchen versucht: Meine aktuelle Konfiguration ist dies (in persistence.xml):
<property name="eclipselink.jdbc.bind-parameters" value="true"/>
<property name="eclipselink.jdbc.cache-statements" value="true"/>
<property name="eclipselink.cache.size.default" value="10000"/>
<property name="eclipselink.query-results-cache" value="true"/>
Ich weiß nicht, ob es die effizienteste Konfiguration ist, und ich würde mich über Hilfe und einige Erklärungen zum JPA-Cache freuen.
Danke.
Was machen getByCodePays und getByCodePostalAndVilleAndINSEE? Und hast du schon einen Profiler benutzt? –
Haben Sie überprüft, welcher Teil der Engpass Ihrer Implementierung ist? Führen Sie Prüfungen durch, die von der Anzahl der Datenbankelemente beeinflusst werden können? – Eypros
Gibt es eine Möglichkeit, große Dateien in kleinere Dateien zu zerlegen. Und dann durch Executor, lesen Sie jedes Segment und Prozess? –