Bonjour à tous,
je travaille actuellement, dans un cadre professionnel, sur un projet J2EE utilisant Hibernate pour le mapping o/r. La base de données sur laquelle je travaille contient plusieurs tables relativement similaires, contenant différents types de produits. Nous avons donc choisi de les regrouper à l'aide de la stratégie "une table par classe concrète" (http://www.hibernate.org/hib_docs/v3...bleperconcrete), laquelle est représentée par une hiérarchie de classes du côté objet.
Après quelques petits soucis, nous avons réussi à mapper le tout pour que cela fonctionne. Malheureusement, ces différentes tables contiennent plusieurs millions de lignes chacune, ce qui a tendance à très fortement dégrader les performances d'Hibernate, étant donné que les requêtes qu'ils génèrent ne sont pas des plus rapides. Je m'explique :
Voici un exemple (que j'ai volontairement simplifié et en partie renommé) de la requête SQL générée par Hibernate pour récupérer un ensemble de produits, contenus dans les différentes tables, mais rattachés à la même commande :
Etant donné le nombre de lignes contenues dans les différentes tables, cette requête prend plusieurs minutes pour s'exécuter (mon record doit tourner autour de 20 min !!). Ceci est dû au "select" central travaillant avec l'"union".
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
16
17
18
19
20
21
22
23
24
25
26
27 select produits0_.libelle as libelle3_, produits0_.num_commande as num_commande41_2_, produits0_.a_envoyer as a5_41_2_, produits0_.clazz_ as clazz_2_ from ( select libelle, num_commande, a_envoyer, 1 as clazz_ from produit_1 union select libelle, num_commande, a_envoyer, 2 as clazz_ from produit_2 ) produits0_ where produits0_.num_commande=?
En effet, il suffit de transformer la requête comme suit pour que le même résultat soit obtenu en 0,01s :
Etant donné que je possède le code de la requête beaucoup plus rapide, j'aurai pu l'implémenter directement dans le code et trouver un moyen de convertir les résultats dans les différentes classes concernées.
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
16
17
18
19
20
21
22
23
24
25
26
27 select produits0_.libelle as libelle3_, produits0_.num_commande as num_commande41_2_, produits0_.a_envoyer as a5_41_2_, produits0_.clazz_ as clazz_2_ from ( select libelle, num_commande, a_envoyer, 1 as clazz_ from produit_1 where num_commande=? union select libelle, num_commande, a_envoyer, 2 as clazz_ from produit_2 where num_commande=? ) produits0_
Le problème est que cette requête est générée automatiquement lorsque Hibernate essaye de récupérer une collection de produits, appartenant à une commande en tant qu'attribut (nous avons activé l'option Lazy-loading pour limiter le nombre de données chargées). Nous n'y avons donc pas accès.
Connaissez-vous un moyen (en mappant différemment les tables, avec une option Hibernate à activer...) d'améliorer les performances des requêtes générées automatiquement par Hibernate ou encore de donner à Hibernate les requêtes à utiliser pour les sélectionner les attributs souhaités ?
Merci d'avance pour vos réponses,
MiniMarch
Partager