2010-11-09 24 views
1

J'utilise la récupération par lots d'hibernate pour améliorer les performances des requêtes. Dans mon persistence.xml j'ai ajouté le paramètre suivant:Mise en veille prolongée: ordre de récupération inattendu pour l'extraction par lots

<property name="hibernate.default_batch_fetch_size" value="50"/> 

J'ai une entité A, qui a un 1: n rapport à une entité B. Les données de ce rapport sont extraites paresseusement. Maintenant, j'ai la situation suivante:.

  • je charge 10000 entités de type A de DB
  • J'itérer sur ces entités et initialisez la relation paresseuse en appelant a.getBs() taille()
  • En faisant cela, hibernate n'initialise pas seulement la dépendance de l'entité courante, mais charge en plus la dépendance de 49 entités supplémentaires de la liste. Ce comportement est attendu

Le SQL généré ressemble à ceci:

select 
    b0_.SOMETHING as SOMETHING1_1_, 
    ... 
from 
    XYZ.B b0_ 
where 
    b0_.A_ID in (
     ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ... 
    ) 

Mon vrai problème est que veille prolongée ne se charge pas les entités de la liste des résultats dans l'ordre attendu. Lorsque j'accède à la première entrée de la liste, elle ne charge pas les données pour les entités 2-50, mais charge les données pour 49 entrées aléatoires de la liste. (par exemple, il peut initialiser les données des entités 3, 7, 100, 2001, ...). Ce comportement est assez étrange et je me demande comment le changer pour charger les données dans l'ordre attendu.

Problèmes courants liés au comportement décrit.

  • Utilisation de la mémoire. Pendant l'itération de la liste, Hibernate initialise beaucoup de données, ce qui sera BEAUCOUP plus tard. En plus de l'algorithme ci-dessus, j'ai ajouté du code, qui supprime les enregistrements traités de la liste et appelle session.evict (entité), pour rendre l'entité éligible pour la récupération de place. Ceci ne fonctionne bien sûr pas maintenant.
  • La vitesse de requête est très lente au début de l'itération car Hibernate interroge la base de données pour presque toutes les entités traitées. Cela provoque des problèmes car j'écris les entités dans le flux d'une application Web pour téléchargement lors du traitement. En conséquence, la vitesse de téléchargement est très lente au début et accélère lorsque plus d'entités ont été chargées en mémoire et que moins d'appels db sont requis.

Merci beaucoup pour votre aide et meilleures salutations

Thomas

+0

Utilisez-vous les listes itérateur()? – KarlP

+0

J'ai testé l'itérateur et la nouvelle boucle for (pour (A a: resultlist)) – Thomas

Répondre

2

Quand vous dites que Hibernate ne se charge pas les entités dans l'ordre attendu, avez-vous dit que ce que l'ordre attendu est? Autrement dit, le mappage pour les B contient-il un attribut order-by? Si ce n'est pas le cas, alors ils ont aucun ordre dans le modèle de données Hibernate et peuvent être chargés dans n'importe quel ordre (probablement la base de données par défaut). Sinon, d'après ce que je comprends, Hibernate devrait appliquer la contrainte order-by lors de la recherche des pkeys à charger. Par conséquent, il pourrait être utile de prendre cela sur les listes de diffusion comme un bug potentiel.