-->
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.  [ 5 posts ] 
Author Message
 Post subject: Reduce queries made from relationships
PostPosted: Tue Jan 30, 2007 6:02 pm 
Newbie

Joined: Tue Jan 30, 2007 5:26 pm
Posts: 7
I'm using Hibernate Core 3.2.2 and Annotation/EntityManager 3.2.1 with JPA for my web app powered by Tomcat and mySQL.

The problem I'm having is that a single page load can run over 190 queries with only a few things in my tables. I'd like to figure out how to reduce this. It seems that Hibernate is just doing 1+n queries instead of joining them, but I can't find out what I need to use to make them join. Here's a many-to-many relationship that I'm trying to reduce:

Code:
@Entity
public class Affiliate implements Serializable {
   
    private int id;
    private List<Product> product = new ArrayList<Product>();
   
    /** Creates a new instance of Affiliate */
    public Affiliate() {
    }

    @GeneratedValue
    @Id
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
   
    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(
        name="Product_Affiliate",
            joinColumns={@JoinColumn(name="affiliate_id")},
            inverseJoinColumns={@JoinColumn(name="product_id")}
    )
    @Fetch(value=FetchMode.JOIN)
    public List<Product> getProduct() {
        return product;
    }

    public void setProduct(List<Product> product) {
        this.product = product;
    }
   
}

@Entity
public class Product implements Serializable {

    private List<Affiliate> affiliates = new ArrayList<Affiliate>();
    private Set<Schedule> schedule = new HashSet<Schedule>();
   
    private int id;
    private String title;
    private double price;
    private int capacity;
    private boolean active;
   
   
    /** Creates a new instance of Product */
    public Product() {
    }
   
    @GeneratedValue
    @Id
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @ManyToMany(mappedBy = "product")
    public List<Affiliate> getAffiliates() {
        return affiliates;
    }

    public void setAffiliates(List<Affiliate> affiliates) {
        this.affiliates = affiliates;
    }

    @OneToMany(cascade=javax.persistence.CascadeType.ALL, mappedBy="product",fetch=FetchType.EAGER)
    @Fetch(value=FetchMode.JOIN)
    public Set<Schedule> getSchedule() {
        return schedule;
    }

    public void setSchedule(Set<Schedule> schedule) {
        this.schedule = schedule;
    }
   
}

@Entity
public class Schedule implements Serializable {
    private int id;
    private Date date;
    private Product product;
   
    /** Creates a new instance of Schedule */
    public Schedule() {
    }

    @GeneratedValue
    @Id
    public int getId() {
        return id;
    }

    protected void setId(int id) {
        this.id = id;
    }
   
    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="product_id", nullable=false)
    public Product getProduct() {
        return product;
    }
   
    public void setProduct(Product product) {
        this.product = product;
    }

}


These have a few fields pruned to save length. Then I'm calling this to eagerly fetch all Affiliates with their associated Products:

Code:
EntityManager em = emf.createEntityManager();
Collection<Affiliate> colx = em.createQuery("select obj from Affiliate obj").getResultList();
em.close();
emf.close();


And it ends up generating a whole mess of queries. It's doing one query to fetch all the affiliates, then running n queries to fetch the products from each affiliate. It also runs one query for each Schedule.



With 6 Affiliates, 6 Products, and 2 Schedules, Hibernate ends up running all this, when executing: em.createQuery("select obj from Affiliate obj").getResultList();

Code:
Hibernate: select affiliate0_.id as id4_, affiliate0_.contact as contact4_, affiliate0_.main as main4_, affiliate0_.title as title4_ from Affiliate affiliate0_
Hibernate: select product0_.affiliate_id as affiliate1_1_, product0_.product_id as product2_1_, product1_.id as id0_0_, product1_.price as price0_0_, product1_.capacity as capacity0_0_, product1_.active as active0_0_, product1_.title as title0_0_ from Product_Affiliate product0_ left outer join Product product1_ on product0_.product_id=product1_.id where product0_.affiliate_id=?
Hibernate: select product0_.affiliate_id as affiliate1_1_, product0_.product_id as product2_1_, product1_.id as id0_0_, product1_.price as price0_0_, product1_.capacity as capacity0_0_, product1_.active as active0_0_, product1_.title as title0_0_ from Product_Affiliate product0_ left outer join Product product1_ on product0_.product_id=product1_.id where product0_.affiliate_id=?
Hibernate: select product0_.affiliate_id as affiliate1_1_, product0_.product_id as product2_1_, product1_.id as id0_0_, product1_.price as price0_0_, product1_.capacity as capacity0_0_, product1_.active as active0_0_, product1_.title as title0_0_ from Product_Affiliate product0_ left outer join Product product1_ on product0_.product_id=product1_.id where product0_.affiliate_id=?
Hibernate: select product0_.affiliate_id as affiliate1_1_, product0_.product_id as product2_1_, product1_.id as id0_0_, product1_.price as price0_0_, product1_.capacity as capacity0_0_, product1_.active as active0_0_, product1_.title as title0_0_ from Product_Affiliate product0_ left outer join Product product1_ on product0_.product_id=product1_.id where product0_.affiliate_id=?
Hibernate: select schedule0_.product_id as product3_1_, schedule0_.id as id1_, schedule0_.id as id2_0_, schedule0_.product_id as product3_2_0_, schedule0_.coursedate as coursedate2_0_ from Schedule schedule0_ where schedule0_.product_id=?
Hibernate: select schedule0_.product_id as product3_1_, schedule0_.id as id1_, schedule0_.id as id2_0_, schedule0_.product_id as product3_2_0_, schedule0_.coursedate as coursedate2_0_ from Schedule schedule0_ where schedule0_.product_id=?
Hibernate: select schedule0_.product_id as product3_1_, schedule0_.id as id1_, schedule0_.id as id2_0_, schedule0_.product_id as product3_2_0_, schedule0_.coursedate as coursedate2_0_ from Schedule schedule0_ where schedule0_.product_id=?
Hibernate: select product0_.affiliate_id as affiliate1_1_, product0_.product_id as product2_1_, product1_.id as id0_0_, product1_.price as price0_0_, product1_.capacity as capacity0_0_, product1_.active as active0_0_, product1_.title as title0_0_ from Product_Affiliate product0_ left outer join Product product1_ on product0_.product_id=product1_.id where product0_.affiliate_id=?
Hibernate: select schedule0_.product_id as product3_1_, schedule0_.id as id1_, schedule0_.id as id2_0_, schedule0_.product_id as product3_2_0_, schedule0_.coursedate as coursedate2_0_ from Schedule schedule0_ where schedule0_.product_id=?
Hibernate: select schedule0_.product_id as product3_1_, schedule0_.id as id1_, schedule0_.id as id2_0_, schedule0_.product_id as product3_2_0_, schedule0_.coursedate as coursedate2_0_ from Schedule schedule0_ where schedule0_.product_id=?
Hibernate: select schedule0_.product_id as product3_1_, schedule0_.id as id1_, schedule0_.id as id2_0_, schedule0_.product_id as product3_2_0_, schedule0_.coursedate as coursedate2_0_ from Schedule schedule0_ where schedule0_.product_id=?
Hibernate: select product0_.affiliate_id as affiliate1_1_, product0_.product_id as product2_1_, product1_.id as id0_0_, product1_.price as price0_0_, product1_.capacity as capacity0_0_, product1_.active as active0_0_, product1_.title as title0_0_ from Product_Affiliate product0_ left outer join Product product1_ on product0_.product_id=product1_.id where product0_.affiliate_id=?




This seems so excessive. Is there some way to reduce this? Have I screwed up my annotations/mapping somehow?[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 30, 2007 6:36 pm 
Regular
Regular

Joined: Mon Nov 14, 2005 7:33 pm
Posts: 73
This is why eager fetching is not the best way to go, you need to lazy-fetch by setting them to LAZY and use "left join fetch" to call out the objects/collections you need.

The only time I use eager fetching, which is very rare, is when I know that the number of records will be very limited and there is no potential for n number of queries being executed out of my control. This use case doesn't arise very often...and I'll still avoid it if I don't *need* eager fetching.

The hibernate docs have very clear, excellent examples on how to do this, and it's quite easy.

Hope this helps!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 30, 2007 8:51 pm 
Newbie

Joined: Tue Jan 30, 2007 5:26 pm
Posts: 7
Yeah, I'd prefer to do lazy fetching. But the problem with that is I'm using struts so the place where I'd need to fetch the collections (in the JSPs using Struts Taglibs) is out of reach of the EntityManager. It seems like using Struts with JPA was the wrong approach and should have picked some other MVC framework.

Is there some solution for using lazy fetching with Struts?

And still, regardless of lazy/eager fetching, this still seems like a ridiculous amount of queries to be running.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 31, 2007 2:47 pm 
Regular
Regular

Joined: Mon Nov 14, 2005 7:33 pm
Posts: 73
gharding wrote:
Yeah, I'd prefer to do lazy fetching. But the problem with that is I'm using struts so the place where I'd need to fetch the collections (in the JSPs using Struts Taglibs) is out of reach of the EntityManager. It seems like using Struts with JPA was the wrong approach and should have picked some other MVC framework.

Is there some solution for using lazy fetching with Struts?

And still, regardless of lazy/eager fetching, this still seems like a ridiculous amount of queries to be running.


It sounds to me (and I'm just speculating here) that your flaws like in your architecture and design rather than the chosen framework.

In order to lazily-fetch related entities, you just need to make sure you're doing so *before* you return the results to the view (in most frameworks.)

I use Wicket, mostly, in the context of EJB 3.0 (JBoss 4.0.x) applications and I simply query my lazily-loaded collections/entities at the Session Bean level before returning them to the view in the web project...which in Wicket is just a POJO.

If you're in the market for a new web framework, I'd highly recommend Wicket - not to get too far off topic. It's simple, fun, and extremely powerful...and no XML configuration necessary.

Back to the topic - if you post some code samples maybe we can shoot holes in it for you! ;)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 02, 2007 5:59 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
please rate posts when they help you.

_________________
Emmanuel


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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.