-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: one-to-one bidirectional association results in n+1 selects
PostPosted: Thu Dec 16, 2010 6:25 pm 
Newbie

Joined: Thu Dec 16, 2010 4:09 pm
Posts: 4
I have found a lot of threads on this but none with any resolution of the issue.

Succinctly, the problem is that with one-to-one bidirectional associations Hibernate for some reason will retrieve the other end of the association individually for each entity returned, i.e. you get n+1 selects. Yuck.

I'm running Hibernate 3.6.0 (on MySQL, but I don't think that matters). My model is:

Code:
@Entity
class Parent {
   @Id @GeneratedValue
   private long id;

   @OneToOne( mappedBy = "parent" )
   private Child child;
}

@Entity
class Child {
   @Id @GeneratedValue
   private long id;
   
   @OneToOne( optional = false )
   @JoinColumn( name = "parent_id" )
   private Parent parent;
}


(getters and setters omitted for brevity)

Let's say I do something nice and simple like:

Code:
session.createQuery("from Parent").list();


I would expect to see a query like "select * from Parent left outer join Child on Parent.id = Child.parent_id", which gets us everything we need. Instead, Hibernate does this:

Hibernate: select parent0_.id as id12_ from Parent parent0_
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?

i.e. let's get a list of all of the parents (there are 5 in the database), and then individually select each child.

Similar behavior happens for "from Child", but even worse - there are now TWO queries for each of the four children:

Hibernate: select child0_.id as id13_, child0_.parent_id as parent2_13_ from Child child0_
Hibernate: select parent0_.id as id12_1_, child1_.id as id13_0_, child1_.parent_id as parent2_13_0_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id where parent0_.id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select parent0_.id as id12_1_, child1_.id as id13_0_, child1_.parent_id as parent2_13_0_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id where parent0_.id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select parent0_.id as id12_1_, child1_.id as id13_0_, child1_.parent_id as parent2_13_0_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id where parent0_.id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select parent0_.id as id12_1_, child1_.id as id13_0_, child1_.parent_id as parent2_13_0_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id where parent0_.id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?

If I say "from Parent as parent left join fetch parent.child", I get the behavior I expected:

Hibernate: select parent0_.id as id12_0_, child1_.id as id13_1_, child1_.parent_id as parent2_13_1_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id

Okay, fine, it's somewhat obnoxious to have to make sure I left join fetch the child in every query (especially if there are multiple one-to-one associations), but whatever. There should be a better way to do this. And I still haven't figured out how to do this for Child - the analogous query only cuts the number of queries by half. I want to do this in one query.

Does anyone know why this happens, and a consistent way to prevent it?

PS: I don't care about lazily loading child, as many of the other people posting about this do - I just don't want to run one query for each row in my table!


Top
 Profile  
 
 Post subject: Re: one-to-one bidirectional association results in n+1 selects
PostPosted: Mon Dec 20, 2010 11:43 am 
Newbie

Joined: Thu Dec 16, 2010 4:09 pm
Posts: 4
No one knows anything about this?


Top
 Profile  
 
 Post subject: Re: one-to-one bidirectional association results in n+1 selects
PostPosted: Thu Dec 23, 2010 2:41 pm 
Newbie

Joined: Thu Dec 16, 2010 4:09 pm
Posts: 4
I have finally succumbed and done the awful, horrible thing that Hibernate forces me to: replacing the parent attribute with a ManyToOne that only ever has 0 or 1 elements. There is absolutely no conceivable reason why I should have to do this. I have found tons of posts in this forum, on StackOverflow, etc. with this same issue - it's apparently been around since at least version 3.0 - but I've never seen a developer acknowledge it.

Particularly galling is the fact that OneToOne associations literally ignore the @Fetch annotation. At query time the value is just discarded. (I looked through the source.)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.