Bonsoir,
J'ai une structure de donnée de type arbre :
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 : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 class Noeud { Integer Id ;//sequence Noeud precedent; // référence au noeud precédent String donnee; }
Les appels à hibernate sont localisés dans getRacines(); et getSuivants(courant) ;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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()); } }
La requete dans getSuivants et de ce genre :
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).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 List getSuivants(courant) { Query query = session.getQuery("from Noeud where precedent=:courant").setEntity("courant",courant); return query.list(); }
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 :
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).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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(); } }
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
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.
Partager