Question

J'utilise l'implémentation de JPA par Hibernate et je constate des performances médiocres, car plusieurs requêtes SQL sont émises pour chaque entité extraite. Si j’utilise une requête JPA jointe, elle ne génère qu’une requête SQL mais ne trouve pas de ligne car la relation sera nulle.

Exemple, considérons ce schéma simple. Une personne habite à une adresse et est employée par une entreprise. L’adresse et l’employeur sont facultatifs et peuvent donc être nuls.

@Entity
public  class Person {
    public name;

    @ManyToOne
    @Column(nullable=true)
    public Address address

    @ManyToOne
    @Column(nullable=true)
    public Company employer
}

@Entity
public  class Address {
    address attributes ...
}

@Entity
public  class Company {
    company attributes ...
}

N'est pas indiqué ci-dessus que chaque entité JPA possède une sorte d'identifiant (clé):

@Id
public Integer id;

Le problème que je vois est qu’une seule requête JPA sur Person génère plusieurs requêtes SQL sur la base de données. Par exemple, la requête JPA suivante:

select p from Person p where ...

résultats dans la requête SQL:

select ... from Person where ...

et la paire de requêtes SQL suivante pour chaque personne extraite:

select ... from Address a where a.id=xxx
select ... from Company c where c.id=yyy

Cela a un impact énorme sur les performances. Si le résultat de la requête est défini sur 1 000 personnes, il génère 1 + 1000 + 1000 = requêtes SQL 2001.

J'ai donc essayé d'optimiser la requête JPA en la forçant à se joindre:

select p from Person p join p.address a join p.employer e where ...

ou:

select p, a, e from Person p join p.address a join p.employer e where ...

Cela se traduit par une seule requête SQL avec un ensemble de jointures. Le problème est que si adresse ou employeur est null, la requête jointe ne le trouvera pas.

Il me reste donc à utiliser soit la requête sans jointure qui est lente, soit la requête jointe rapide qui ne récupère pas de lignes aura des relations nulles. Je dois manquer quelque chose ici. Il existe sûrement un moyen d'effectuer des requêtes rapides et complètes.

Était-ce utile?

La solution

Je pense que vous auriez besoin d'une jointure gauche, c'est-à-dire

.
SELECT p FROM Person p LEFT JOIN p.address a LEFT JOIN p.employer e WHERE...

Voir cette entrée de blog comme exemple

Notez que je n'ai pas réellement essayé cela avec JPA, mais cela fonctionne très bien avec HQL, qui constitue la base du standard JPA à bien des égards.

La raison pour laquelle cela ne fonctionne pas avec les jointures simples est que la valeur par défaut est une jointure interne.

Autres conseils

Essayez de définir une taille de lot (@BatchSize) sur les entités Address et Company. Il ne les chargera pas dans une jointure (est-ce ce que vous recherchez?), Mais il en chargera plusieurs à chaque chargement. La taille de lot indique combien il doit en charger quand elle découvre qu’elle en a besoin.

Si vous avez une taille de lot de 1 (valeur par défaut) et chargez 10 personnes. Ensuite, parcourez-les en lisant leur adresse et les éléments de leur entreprise, puis Hibernate fera une requête pour les 10 personnes, puis chaque fois qu'il aura besoin de l'adresse ou de la société de l'une de ces personnes, il demandera l'adresse de cette personne.

Si vous avez défini une taille de lot de 7 sur l'entité Adresse, lorsque vous lirez la première adresse, il verra qu'il y a plus de 7 adresses actuellement mandatées et ira vous chercher 7 adresses.

Si vous avez à la fois Address et Company avec un BatchSize de 7 et que vous parcourez 10 personnes, cela entraînera 5 requêtes, au lieu des 21 ans pour le moment. Pas encore le 1 qu'une jointure vous donnerait. Cependant, la jointure serait plus lente dans les cas où vous ne souhaitiez que les objets Personne et que vous n'allez pas toucher les entités Adresse / Société incorporées dans ces objets (par exemple, vous voulez simplement obtenir une liste des identifiants de personne, ou compter sont des hommes / femmes)

Regardez: http://hibernate.org/hib_docs/v3/reference/en/ html / performance.html

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top