2008-12-23 7 views
0

Je crée une application Web de base de données en utilisant l'implémentation JPA de Java et Hibernate. L'application suit les objets. Il doit également importer par lots des objets à partir d'une source héritée. Par exemple, disons que nous suivons des personnes. Par exemple, par exemple. La base de données contient des tables appelées Person et Address. Il y a des entités JPA et des classes DAO correspondantes.Conseil sur les performances de la base de données lors de l'importation par lots de jeux de données volumineux

Au-dessus de la couche JPA se trouve une couche de service responsable de diverses opérations. Une opération consiste à importer un ensemble de données potentiellement important à partir d'une source héritée externe (par exemple, les personnes d'un annuaire téléphonique). Pour chaque personne, elle doit vérifier si elle existe déjà dans la base de données. Ensuite, il doit créer ou mettre à jour la personne si nécessaire. Chaque personne a une adresse donc la référence croisée appropriée et la création d'adresse doivent également se produire.

Mon problème est que cette opération peut être lente pour les grands ensembles de données. Mon algorithme actuel est:

for (Person person: allPersons) 
{ 
    check if person exists in database 
    check if address exists in database 
    create or update person and address as necessary 
} 

Que recommanderiez-vous pour améliorer les performances?

Du haut de ma tête, je peux penser à:

  1. Modifier la logique d'importation pour récupérer et stocker des données à la base de données en utilisant des requêtes. Par exemple, au lieu de vérifier si la personne existe dans la boucle for, soumettez toutes les clés de la personne à la base de données en une seule requête. Le processus traite chaque personne récupérée en mémoire.
  2. Ajouter ma propre mise en cache dans les classes DAO.
  3. Utilisez une solution de mise en cache externe (telle que memcached).

Je peux toujours aller aveC# 1 en restructurant pour minimiser les requêtes. L'inconvénient est que ma couche de service est maintenant très au courant de la couche DAO. Sa mise en œuvre est maintenant dictée par la couche de base de données inférieure. Il y a aussi d'autres problèmes comme l'utilisation de trop de mémoire. Ce grab-from-database-then-process-in-memory semble très propre et va à l'encontre des solutions prêtes à l'emploi comme JPA. Je suis curieux de savoir ce que les autres feraient dans ce cas. Editer: La mise en cache ne va pas aider car chaque personne interrogée dans la boucle est différente.

Répondre

1

Voici deux solutions que j'ai trouvé qui fonctionnent. L'un consiste à traiter un morceau à la fois. Après chaque tronçon fermant un redémarrage de la session. J'ai essayé d'utiliser les méthodes flush clear sur la session mais parfois cela fonctionne comme vous l'attendez. Démarrer et arrêter la transaction entre les lots semble fonctionner le mieux.

Si la performance est une préoccupation majeure, il vous suffit de décomposer et de le faire en JDBC. Hibernate ajoute trop de frais généraux pour le traitement par lots de grands ensembles de données, où la mémoire et les performances sont importantes.

+1

L'une des raisons pour lesquelles flush ne Toujours libérer de la mémoire est que Hibernate va stocker des références à tous les objets sauvegardés dans la transaction afin qu'il puisse appeler des hooks post-commit sur les objets, le cas échéant, à la fin de la transaction. – davidsheldon

0

Votre approche va entraîner trop de requêtes individuelles sur la base de données; ressemble à 4n + 1. Si possible, je voudrais écrire une requête (peut-être en SQL brut) qui vérifie l'existence de personne + adresse tout en un seul coup.

Vous pouvez travailler avec StatelessSession au lieu de la session Hibernate standard. Comme il n'a pas de cache de 1er niveau, il devrait réduire vos besoins en mémoire.

http://www.hibernate.org/hib_docs/reference/en/html/batch-statelesssession.html

Si cela ne fonctionne pas pour vous, alors vous aurez envie de jeter un oeil sur les options de traitement par lots dans Hibernate:

http://www.hibernate.org/hib_docs/reference/en/html/batch.html

Questions connexes