Chargement de données, parcours arbre, Exploitation du cache
Bonsoir,
J'ai une structure de donnée de type arbre :
Code:
1 2 3 4 5
| class Noeud {
Integer Id ;//sequence
Noeud precedent; // référence au noeud precédent
String donnee;
} |
Grosso Modo, je developpe un batch et l'algorithme de mon programme part d'un ou plusieurs noeud initiaux (racines) jusqu'a un ou plusieurs noeuds finaux. Ci dessous l'algorithme en pseudo code "java".
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
recupererSolutions() {
List racines = getRacines(); // getRacines utilise hibernate pour récuperer l
while (racines.iteartor.hasnext()) {
parcourirArbre((Noeud)racines.iteartor.next());
}
}
parcourirArbre(Noeud courant) {
Si (courant==null || isFeuille(courant)) return;
List suivants = getSuivants(courant) ; // utilise hibernate
while (suivants.iteartor.hasnext()) {
parcourirArbre((Noeud)suivants.iteartor.next());
}
} |
Les appels à hibernate sont localisés dans getRacines(); et getSuivants(courant) ;
La requete dans getSuivants et de ce genre :
Code:
1 2 3 4
| List getSuivants(courant) {
Query query = session.getQuery("from Noeud where precedent=:courant").setEntity("courant",courant);
return query.list();
} |
Voici mon problème : Hibernate effectue une requete en base pour chaque Noeud suivant. Conséquence mon application est très lente (j'ai des milliers d'enregistrements Noeuds donc des millers d'accès en base).
Mon idée pour résoudre le problème est de charger tous les Noeuds en mémoire avant l'appel de la fonction récursive parcourirArbre() dans recupererSolutions().
Je me suis dit qu'hibernate pouvait bien faire ça sans que je me "fatigue" à creer des Map à tire la rigo. Je charge donc tous les noeuds puis j'utilise la même session dans getSuivants().
En gros :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
Session s = new SessionImpl(); // donnée membre
recupererSolutions() {
List racines = getRacines(); // getRacines utilise hibernate pour récuperer l
loadAll(); // Recupère toutes les peristants Noeud en base sur la session S
while (racines.iteartor.hasnext()) {
parcourirArbre((Noeud)racines.iteartor.next());
}
List getSuivants(courant) {
Query query = session.getQuery("from Noeud where precedent=:courant",s).setEntity("courant",courant);
return query.list();
}
} |
Voilà, après execution et mesure des performances, j'observe en effet une amélioration d'une facteur d'un peu plus du tiers (1/3).
Cependant, cette amélioration me semble insuffisante, après tout l'accès mémoire et beaucoup plus rapide qu'une connexion à la base.
Et lorsque je regarde la log générée par hibernate, il m'indique qu'il execute des prepared statment puis qu'il trouve l'entité en proxy :aie:
Alors je ne comprend pas, hibernate fait t'il réellement un accès en base ? Cette lenteur est elle normale ?? Y'a t'il trop d'objets dans la session et du coup la recherche des entités est plus longue (pb mémoire) ??? Y'at'il des solutions bien connues pour ce genre de problème (parcours d'un arbre)??
Merci d'avoir lu et, je remercie par avance les bonnes âmes qui se pencherons sur mon problème. :)