2009-01-21 6 views
3

Y a-t-il une limite au nombre de jointures autorisées dans une requête JPA/Hibernate?JPA/Hibernate nombre maximum de jointures?

Depuis Hibernate doesn't automatically join, je dois spécifier explicitement les jointures dans ma requête JPA/Hibernate. Par exemple, une personne a une adresse, une adresse a un état. La requête suivante extrait personne (s) avec adresse et état complètement chargé:

select p, a, s from person p left join p.address a left join a.state s where ... 

Comme je continuer à ajouter les jointures, j'ai finalement (après 12-13 gauche rejoint) atteignent une limite où Hibernate génère SQL invalide:

Caused by: java.sql.SQLException: Column 'something69_2_' not found. 

J'ai le dialecte de Hibernate mis à ma mise en œuvre de la base de données, MySQL:

<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> 

y at-il une limite au nombre Hibernate peut gérer des jointures dans une seule requête?

Edit 1: Ce qui suit est dans le fichier journal:

could not read column value from result set: something69_2_; Column 'something69_2_' not found. 

Cependant, something69_2_ ne figure pas dans la requête SQL. C'est comme si Hibernate avait généré une requête SQL et attendait something69_2_ dans les résultats, ce qui n'est pas le cas.

Edit 2: problème similaire documenté comme unfixed Hibernate bug HHH-3035

Edit 3: Ce est documenté Hibernate bug HHH-3636, qui a été fixé, mais ne fait pas partie d'une sortie pour le moment.

Édition 4: J'ai construit hibernate-core 3.3.2-SNAPSHOT qui inclut la correction de bogue HHH-3636 et il n'a pas résolu ce problème.

Édition 5: Le comportement de bogue semble être déclenché par plusieurs LEFT JOIN FETCH sur les relations ManyToMany ou OneToMany. On va travailler, deux ou trois résultats dans le bug.

Modifier 6: Voici la trace de la pile:

javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query 
     at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:629) 
     at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:73) 
Caused by: org.hibernate.exception.SQLGrammarException: could not execute query 
     at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67) 
     at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43) 
     at org.hibernate.loader.Loader.doList(Loader.java:2214) 
     at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2095) 
     at org.hibernate.loader.Loader.list(Loader.java:2090) 
     at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:388) 
     at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:338) 
     at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:172) 
     at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1121) 
     at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79) 
     at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:64) 
     ... 69 more 
Caused by: java.sql.SQLException: Column 'something69_2_' not found. 
     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) 
     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) 
     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926) 
     at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1136) 
     at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2777) 
     at org.hibernate.type.IntegerType.get(IntegerType.java:28) 
     at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:113) 
     at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:102) 
     at org.hibernate.loader.Loader.getKeyFromResultSet(Loader.java:1088) 
     at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:553) 
     at org.hibernate.loader.Loader.doQuery(Loader.java:689) 
     at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224) 
     at org.hibernate.loader.Loader.doList(Loader.java:2211) 
     ... 77 more 

Modifier 7: La raison de tous ces jointures est d'éviter Hibernate faire n + 1 requêtes, voir Hibernate FAQ on How can I avoid n+1 SQL SELECT queries when running a Hibernate query?

+0

curiosité, la complexité est la clause where dans votre requête JPA? –

+0

La clause where n'a pas d'importance. J'ai essayé 1) clause no where, et 2) clause simple where (WHERE id = 1). –

+0

Pourquoi ne pas utiliser la sous-sélection aller chercher plutôt que de rejoindre alors? – toolkit

Répondre

2

La question est pourquoi essayez-vous de faire une telle requête complexe en premier lieu?

Avez-vous envisagé différentes approches? La documentation sur improving performance fait quelques suggestions.

+0

Sans les jointures, Hibernate fera n + 1 requêtes causant de très mauvaises performances. Voir http://www.hibernate.org/118.html#A23 –

+0

Non correct - voir l'approche sous-sélection. – toolkit

1

Il y a rien dans le code Hibernate qui limite le nombre de jointures. Cela pourrait être un bug dans le dialecte, ou une limitation du moteur de base de données. Mais mon argent est sur un bug sans rapport avec le nombre de jointures! Avez-vous essayé d'exécuter le SQL directement dans une session de requête interactive?

+0

La requête SQL fonctionne très bien. Le problème est que Hibernate essaie de lire un champ de résultat qui n'existe pas. –

1

J'ai une fois atteint la limite de table MySQL 5.0 61 avec Hibernate:

ERROR 1116 (HY000): Too many tables; MySQL can only use 61 tables in a join
+0

J'ai moins de 20 tables. –

0

Avez-vous essayé d'exécuter avec le pilote jdbc réel en cours d'utilisation? Ce pourrait être un problème du pilote jdbc.

Bien que le nom de la colonne soit à la recherche d'un nom, je suppose qu'il y a une sorte de découpage/construction de noms qui ne va pas. Vraiment ressemble plus à un bug qu'à une limite prévue.

0

Est-ce que vous aliasez tous vos de vos jointures internes? Et en utilisant ces alias? J'ai vu un comportement vraiment étrange avec Hibernate lorsque vous essayez d'utiliser aliasing implicite dans la clause SELECT à faire des trucs comme ça (exemple très simplifié):

select p.address.state from person p 

Mais si vous déclarez explicitement tous vos alias il fonctionne très bien . Comme ceci:

select s from person p join p.address a join a.state s 

... ou même ceci:

select s from person p join p.address.state s 
Questions connexes