I’m using Hibernate’s implementation of JPA and am seeing poor performance as multiple SQL queries are issued for each entity that is fetched. If I use a joined JPA query it generates just one SQL query but doesn’t find rows will null relationship.
Example, consider this simple schema. A person lives at an address and is employed by a company. Both address and employer are optional and can thus be null.
@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 ... }
Not shown above is that each JPA entity has some sort of ID (key):
@Id public Integer id;
The problem I’m seeing is that a single JPA query on Person results in multiple SQL queries on the database. For example, the following JPA query:
select p from Person p where ...
results in the SQL query:
select ... from Person where ...
and also the following pair of SQL queries for each retrieved person:
select ... from Address a where a.id=xxx select ... from Company c where c.id=yyy
This has a huge impact on performance. If the query result set is 1000 people, then it generates 1+1000+1000=2001 SQL queries.
So I tried optimizing the JPA query by forcing it to join:
select p from Person p join p.address a join p.employer e where ...
or:
select p, a, e from Person p join p.address a join p.employer e where ...
This results in one single SQL query with a bunch of joins. The problem is if address or employer is null, then the joined query won’t find it.
So I’m left with either using the join-less query which is slow, or the fast joined query that doesn’t retrieve rows will null relationships. I must be missing something here. Surely there’s a way for fast and complete querying.
My guess is that you’d need a left join, i.e.,
See this blog entry for an example
Note that I haven’t actually tried this with JPA, but it works fine in HQL, which is the basis for the JPA standard in many ways.
The reason it’s not working with plain join’s is that the default is an inner join.