简体   繁体   中英

Hibernate generating excessive number of joins in select query

In a Spring MVC app using Hibernate and JPA. Hibernate is creating an excessively complex query with 78 joins when only a small number of joins should be necessary. I am using InhertanceType.JOINED .

To simplify the problem and experiment, I commented out lots of properties in the relevant entities, and I also cut and pasted code from parent classes into subclasses in order to reduce the amount of inheritance. This reduced the number of tables that should be included in joins to 8. But yet when I try an EntityManager.persist() on one of the entities, hibernate generates joins that should not be included. How can I isolate the problem in my code?

You can view a class diagram of the 8 to 12 classes that should be included in joins by clicking on this link . It is a JPEG file that you can enlarge in your browser by clicking on it. There are only 8 to 12 classes that might be included in joins, but Hibernate is including an additional 12 unrelated tables in the joins, which is completely unnecessary. Why?

Here is a list of the Entities that should not be included in the joins:

PQ
QTY
ANY_
SXCMPQ
IVLPQ
BXITIVLPQ
HXITPQ
PPDPQ
SXCMPPDPQ
IVLPPDPQ
IVXBPPDPQ
IVXBPQ

Here is a list of Entities that should be included in the joins:

Person
LivingEntity
rimEntity
Role
CD
TS
II
EN

Here is the DAO method that is throwing the problem:

@Override
    public void saveRIMPerson(Person myperson) throws DataAccessException{
    if (myperson.getHppid() == null) {this.em.persist(myperson);}//EXCESSIVE SQL CREATED HERE
    else {this.em.merge(myperson);}
}  

Here are the joins in the resulting SQL:

Hibernate: select `lots of properties`
 from
 rim_entity person0_ left outer join CD cd1_ on person0_.classCode_HJID=cd1_.HJID
 left outer join TS ivlts2_ on cd1_.VALID_TIME_HXITCE_HJID=ivlts2_.HJID
 left outer join II ids3_ on person0_.hppid=ids3_.ids_entity_HJID
 left outer join CD cd4_ on person0_.administrativeGenderCode_HJID=cd4_.HJID
 left outer join TS ts5_ on person0_.birthTime_HJID=ts5_.HJID
 left outer join PQ pq6_ on ts5_.STANDARD_DEVIATION_PPDTS_HJID=pq6_.HJID
 left outer join QTY pq6_1_ on pq6_.HJID=pq6_1_.HJID
 left outer join ANY_ pq6_2_ on pq6_.HJID=pq6_2_.HJID
 left outer join SXCMPQ pq6_3_ on pq6_.HJID=pq6_3_.HJID
 left outer join IVLPQ pq6_4_ on pq6_.HJID=pq6_4_.HJID
 left outer join BXITIVLPQ pq6_5_ on pq6_.HJID=pq6_5_.HJID
 left outer join HXITPQ pq6_6_ on pq6_.HJID=pq6_6_.HJID
 left outer join PPDPQ pq6_7_ on pq6_.HJID=pq6_7_.HJID
 left outer join SXCMPPDPQ pq6_8_ on pq6_.HJID=pq6_8_.HJID
 left outer join IVLPPDPQ pq6_9_ on pq6_.HJID=pq6_9_.HJID
 left outer join IVXBPPDPQ pq6_10_ on pq6_.HJID=pq6_10_.HJID
 left outer join IVXBPQ pq6_11_ on pq6_.HJID=pq6_11_.HJID
 left outer join CD eivlevent7_ on ts5_.EVENT_EIVLPPDTS_HJID=eivlevent7_.HJID
 left outer join IVLPPDPQ ivlppdpq8_ on ts5_.OFFSET__EIVLPPDTS_HJID=ivlppdpq8_.HJID
 left outer join SXCMPPDPQ ivlppdpq8_1_ on ivlppdpq8_.HJID=ivlppdpq8_1_.HJID
 left outer join PPDPQ ivlppdpq8_2_ on ivlppdpq8_.HJID=ivlppdpq8_2_.HJID
 left outer join PQ ivlppdpq8_3_ on ivlppdpq8_.HJID=ivlppdpq8_3_.HJID
 left outer join QTY ivlppdpq8_4_ on ivlppdpq8_.HJID=ivlppdpq8_4_.HJID
 left outer join ANY_ ivlppdpq8_5_ on ivlppdpq8_.HJID=ivlppdpq8_5_.HJID
 left outer join CD eivlevent9_ on ts5_.EVENT_EIVLTS_HJID=eivlevent9_.HJID
 left outer join IVLPQ ivlpq10_ on ts5_.OFFSET__EIVLTS_HJID=ivlpq10_.HJID
 left outer join SXCMPQ ivlpq10_1_ on ivlpq10_.HJID=ivlpq10_1_.HJID
 left outer join PQ ivlpq10_2_ on ivlpq10_.HJID=ivlpq10_2_.HJID
 left outer join QTY ivlpq10_3_ on ivlpq10_.HJID=ivlpq10_3_.HJID
 left outer join ANY_ ivlpq10_4_ on ivlpq10_.HJID=ivlpq10_4_.HJID
 left outer join BXITIVLPQ ivlpq10_5_ on ivlpq10_.HJID=ivlpq10_5_.HJID
 left outer join TS ppdts11_ on ts5_.CENTER_IVLPPDTS_HJID=ppdts11_.HJID
 left outer join TS ivxbppdts12_ on ts5_.HIGH_IVLPPDTS_HJID=ivxbppdts12_.HJID
 left outer join TS ivxbppdts13_ on ts5_.LOW_IVLPPDTS_HJID=ivxbppdts13_.HJID
 left outer join PPDPQ ppdpq14_ on ts5_.WIDTH_IVLPPDTS_HJID=ppdpq14_.HJID
 left outer join PQ ppdpq14_1_ on ppdpq14_.HJID=ppdpq14_1_.HJID
 left outer join QTY ppdpq14_2_ on ppdpq14_.HJID=ppdpq14_2_.HJID
 left outer join ANY_ ppdpq14_3_ on ppdpq14_.HJID=ppdpq14_3_.HJID
 left outer join SXCMPPDPQ ppdpq14_4_ on ppdpq14_.HJID=ppdpq14_4_.HJID
 left outer join IVLPPDPQ ppdpq14_5_ on ppdpq14_.HJID=ppdpq14_5_.HJID
 left outer join IVXBPPDPQ ppdpq14_6_ on ppdpq14_.HJID=ppdpq14_6_.HJID
 left outer join TS ts15_ on ts5_.CENTER_IVLTS_HJID=ts15_.HJID
 left outer join TS ivxbts16_ on ts5_.HIGH_IVLTS_HJID=ivxbts16_.HJID
 left outer join TS ivxbts17_ on ts5_.LOW_IVLTS_HJID=ivxbts17_.HJID
 left outer join PQ pq18_ on ts5_.WIDTH_IVLTS_HJID=pq18_.HJID
 left outer join QTY pq18_1_ on pq18_.HJID=pq18_1_.HJID
 left outer join ANY_ pq18_2_ on pq18_.HJID=pq18_2_.HJID
 left outer join SXCMPQ pq18_3_ on pq18_.HJID=pq18_3_.HJID
 left outer join IVLPQ pq18_4_ on pq18_.HJID=pq18_4_.HJID
 left outer join BXITIVLPQ pq18_5_ on pq18_.HJID=pq18_5_.HJID
 left outer join HXITPQ pq18_6_ on pq18_.HJID=pq18_6_.HJID
 left outer join PPDPQ pq18_7_ on pq18_.HJID=pq18_7_.HJID
 left outer join SXCMPPDPQ pq18_8_ on pq18_.HJID=pq18_8_.HJID
 left outer join IVLPPDPQ pq18_9_ on pq18_.HJID=pq18_9_.HJID
 left outer join IVXBPPDPQ pq18_10_ on pq18_.HJID=pq18_10_.HJID
 left outer join IVXBPQ pq18_11_ on pq18_.HJID=pq18_11_.HJID
 left outer join PPDPQ ppdpq19_ on ts5_.PERIOD_PIVLPPDTS_HJID=ppdpq19_.HJID
 left outer join PQ ppdpq19_1_ on ppdpq19_.HJID=ppdpq19_1_.HJID
 left outer join QTY ppdpq19_2_ on ppdpq19_.HJID=ppdpq19_2_.HJID
 left outer join ANY_ ppdpq19_3_ on ppdpq19_.HJID=ppdpq19_3_.HJID
 left outer join SXCMPPDPQ ppdpq19_4_ on ppdpq19_.HJID=ppdpq19_4_.HJID
 left outer join IVLPPDPQ ppdpq19_5_ on ppdpq19_.HJID=ppdpq19_5_.HJID
 left outer join IVXBPPDPQ ppdpq19_6_ on ppdpq19_.HJID=ppdpq19_6_.HJID
 left outer join TS ivlppdts20_ on ts5_.PHASE_PIVLPPDTS_HJID=ivlppdts20_.HJID
 left outer join PQ pq21_ on ts5_.PERIOD_PIVLTS_HJID=pq21_.HJID
 left outer join QTY pq21_1_ on pq21_.HJID=pq21_1_.HJID
 left outer join ANY_ pq21_2_ on pq21_.HJID=pq21_2_.HJID
 left outer join SXCMPQ pq21_3_ on pq21_.HJID=pq21_3_.HJID
 left outer join IVLPQ pq21_4_ on pq21_.HJID=pq21_4_.HJID
 left outer join BXITIVLPQ pq21_5_ on pq21_.HJID=pq21_5_.HJID
 left outer join HXITPQ pq21_6_ on pq21_.HJID=pq21_6_.HJID
 left outer join PPDPQ pq21_7_ on pq21_.HJID=pq21_7_.HJID
 left outer join SXCMPPDPQ pq21_8_ on pq21_.HJID=pq21_8_.HJID
 left outer join IVLPPDPQ pq21_9_ on pq21_.HJID=pq21_9_.HJID
 left outer join IVXBPPDPQ pq21_10_ on pq21_.HJID=pq21_10_.HJID
 left outer join IVXBPQ pq21_11_ on pq21_.HJID=pq21_11_.HJID
 left outer join TS ivlts22_ on ts5_.PHASE_PIVLTS_HJID=ivlts22_.HJID
 where person0_.hppid=? and person0_.DTYPE='rimPerson'

The code for the Person entity can be found by clicking on this link . The code for all of the other entities can be found by clicking on this link .

The only thing I can think of is that the underlying MySQL database has many joins on each table, but the database is generated from hbm2ddl using these and other classes as input. Is the problem in my code? Or where else should I look?

While such inter-connected design is valid from an OOP perspective, you must remember that under the hood you are dealing with a relational database, so too much inheritance can hurt performance.

Explaining joins

Your current query root entity is Person, and the provided diagram is misleading because it doesn't say that a Person is a LivingSubject which is a RimEmtity.

The rimEntity.classCode is marked lazy but I see that Hibernate tries to outer join instead. This should not happen, since a second select should load that, so I suspect the code and the error are not in sync, since this association couldn't be found in the CD class either:

left outer join TS ivlts2_ on cd1_.VALID_TIME_HXITCE_HJID=ivlts2_.HJID

Let's take another @ManyToOne, the LivingSubject.birthTime

left outer join TS ts5_ on person0_.birthTime_HJID=ts5_.HJID

So all those are related to @ManyToOne associations of your whole Person class hierarchy.

One possible "solution":

Try setting this property:

hibernate.max_fetch_depth=0

This will disable outer joining and then Hibernate will use additional selects, but that might hurt performance even greater.

Using auto-generated code and hbmddl is a bad design decision. Your DB schema should be generated by incremental update scripts and your Hibernate mappings should map DB tables to Domain Model classes.

Having so many relationships puts a heavy toll on performance so there;s no silver bullet for fixing your problem.

You should design the db tables and the queries first and then decide what's the best domain model to match your application needs.

(Posted the solution on behalf of the question author to move it to an answer post) .

The cause of the problem was that the applicationService.java class had the wrong package name for the datatype being persisted. Thus, the select done by entitymanager was a select of the wrong package's entity of the same name.

The odd part about it was that Eclipse did not seem to complain about the different package. The architecture is that a controller calls the service layer which include applicationService.java and applicationServiceImpl.java , which then calls the repository layer, which includes repository.java and repositoryImpl.java . The wrong package was in the service layer but not in the controller layer or the repository layer. I do not know why Eclipse failed to complain about this. The problem did not show up until runtime.

I am marking Vlad's answer as accepted because he provided a few rounds of very articulate and helpful workarounds.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM