we have a n+1 select problem with Hibernate 3.3.
For simplicity's sake, I'll just do a short abstract example.
Suppose we have the following simple classes:
class MainEntity {
@Id
public Long id; //we have a table generator create this id
@OneToOne ( mappedBy ="main" )
public SubEntity subEntity;
}
class SubEntity {
@Id
@Column( name = "mainId" ) //note that this is the same column as the join column below
public Long mainId; //in order to have the exact same id as the corresponding MainEntity
@OneToOne ( fetch = FetchType.LAZY )
@JoinColumn ( name = "mainId", insertable = false, updatable = false, nullable = false )
public MainEntity main; //this is used for navigation and queries (" ... subentity.main = :x")
}
So as you can see SubEntity
has a relation to MainEntity
that is expressed by two properties, where the mainId
property is the one responsible for managing the relation/foreign key.
This works quite well and perfectly fits our needs.
However, there's one problem with eagerly loading the SubEntity
along with the MainEntity
.
Suppose I have a query that returns a collection of MainEntity
. With the current setup, Hibernate will issue n + 1 selects: the query itself + n selects for each SubEntity
.
Of course I could add a join fetch
to the query, but I'd rather like Hibernate to do that automatically. Thus I tried adding @Fetch( FetchMode.JOIN )
, but that didn't do anything.
I would also have no problem using @Fetch( FetchMode.SUBSELECT )
, which should reduce the select statements to 2 - the original query and a select for the sub entities (at least that's what happens on another property annotated with @CollectionOfElements
and @Fetch( FetchMode.SUBSELECT )
).
So the question is: how would I tell Hibernate to automatically join fetch or use a single select in order to eagerly load the sub entities? Am I missing something?
Thanks in advance,
Thomas
PS: One thing that might be a problem might be the mappedBy = "main"
which doesn't reference the actual id column, but I can't change it to mappedBy = "id"
.
Hibernate N+1 issue occurs when you use `FetchType. LAZY` for your entity associations. Hibernate will perform n-additional queries to load lazily fetched objects. To escape this issue use join fetch, batching or sub select.
The solution to fix the N+1 queries is to configure Hibernate to eagerly fetch the data needed in each query. As I explained before, the best practice is to configure every entity's relationship (ManyToOne…) to be lazily fetched by default.
What is the N+1 query problem. The N+1 query problem happens when the data access framework executed N additional SQL statements to fetch the same data that could have been retrieved when executing the primary SQL query. The larger the value of N, the more queries will be executed, the larger the performance impact.
Hibernate defines the following fetching strategies: Join fetching: Hibernate retrieves the associated instance or collection in the same SELECT , using an OUTER JOIN . Select fetching: a second SELECT is used to retrieve the associated entity or collection.
If you want to shared primary keys between MainEntity and SubEntity use PrimaryKeyJoinColumn
and MapsId
annotation.
By using PrimaryKeyJoinColumn
the entity is loaded
by joining the MainEntity
table with the SubEntity
table using the same primary key. It should resolve the n+1 problems.
The MapsId
annotation ask Hibernate to copy the identifier from
another associated entity in our example will copy the SubEntity.mainEntity.id
to SubEntity.id
.
@Entity
public class MainEntity {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "main_Id")
private Long id;
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private SubEntity subEntity ;
}
@Entity
public class SubEntity
{
@Id @Column(name="main_Id_FK") Long id;
@MapsId
@OneToOne
@JoinColumn(name = "main_Id_FK")
@PrimaryKeyJoinColumn
private MainEntity mainEntity;
}
Hibernate Reference Documentation:
PrimaryKeyJoinColumn
MapsId
There are three options to avoid the questions n +1:
Lot size
subselect
Make a LEFT JOIN in the query
Here FAQ1 Here FAQ2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With