-->
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.  [ 6 posts ] 
Author Message
 Post subject: How to avoid N+1 with lazy one-to-many without outer join?
PostPosted: Fri Mar 11, 2005 10:05 am 
Newbie

Joined: Fri Mar 11, 2005 9:37 am
Posts: 2
I have read the rules and searched the forum. I want to have a 1-M association fetched lazily, but when I do access it, I want it to be retrieved in ONE query instead of N+1 queries. I know I can do this by telling Hibernate to do an outer join to that 1-M association before I get the parent object, but I may not know in advance which 1-M associations might be needed... so I just need it to fetch the 1-M associations efficiently if and when they are accessed.

Hibernate version:2.1

Mapping documents:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping auto-import="false">
    <class name="com.rivermine.model.CustomerRequest" dynamic-update="true" optimistic-lock="none" table="CUSTOMER_REQUEST">
        <id name="crId">
            <column name="CR_ID"/>
            <generator class="uuid.hex"/>
        </id>

        <set name="elements" lazy="true" batch-size="100">
            <key column="CR_ID"/>
            <one-to-many class="com.rivermine.model.CustomerRequestElement"/>
        </set>
    </class>

    <class name="com.rivermine.model.CustomerRequestElement" dynamic-update="true" optimistic-lock="dirty" table="CUSTOMER_REQUEST_ELEMENT">
        <composite-id>
            <key-many-to-one name="customerRequest">
                <column name="CR_ID"/>
            </key-many-to-one>
            <key-property name="sequence">
                <column name="SEQUENCE"/>
            </key-property>
        </composite-id>
        <property name="elementType">
            <column name="ELEMENT_TYPE" length="20" not-null="false"/>
        </property>

        <property name="requestElementData" type="java.io.Serializable">
            <column name="REQUEST_ELEMENT_DATA" length="0" not-null="false"/>
        </property>

    </class>
</hibernate-mapping>


(I have abbreviated the mapping by removing some irrelevant properties.)

Code between sessionFactory.openSession() and session.close():
All I am doing is that I get back an instance of CustomerRequest (which Hibernate retrieves with one query) and then I call getElementCount() on it:
Code:
    public int getElementCount()
    {
        return _elements.size();
    }


where _elements is declared as a java.util.Set.

Full stack trace of any exception that occurs:

Name and version of the database you are using:Oracle 9i

The generated SQL (show_sql=true):
Here is where the real problem is. You'll see Hibernate issue the first, top-level query, which is fine. I then call getElementCount(). In this example, there are 3 "elements". It issues one query against the child table and finds there are 3 rows, which it then re-queries one at a time instead of just building CustomerRequestElements out of the 3-row query. As a result, what could have been done with two queries has taken 5. Not a big deal for 3 child rows but when I have 100, I'm going to have a problem.

Quote:
<Fri Mar 11 08:03:31 EST 2005> <Debug > <sistenceService> <HQL: SELECT a FROM com.rivermine.model.CustomerRequest AS a WHERE (a.crId = :param0)>

08:03:31,229 DEBUG SQL:230 - select customerre0_.CR_ID as CR_ID, customerre0_.ACTUAL_VALUE as ACTUAL_V2_, customerre0_.ADDITIONAL_INFO as ADDITION3_, customerre0_.ASSIGNED_AID as ASSIGNED4_, customerre0_.ASSIGNED_GID as ASSIGNED5_, customerre0_.ASSIGNED_UID as ASSIGNED6_, customerre0_.CR_AUX_ID as CR_AUX_ID, customerre0_.CREATION_DATE as CREATION8_, customerre0_.CURRENT_MILESTONE as CURRENT_9_, customerre0_.CURRENT_MILESTONE_DATE as CURRENT10_, customerre0_.FILE_ID as FILE_ID, customerre0_.MODIFICATION_DATE as MODIFIC12_, customerre0_.ORIGINATING_UID as ORIGINA13_, customerre0_.OWNER_AID as OWNER_AID, customerre0_.OWNER_GID as OWNER_GID, customerre0_.RECORD_STATE as RECORD_16_, customerre0_.REMOTE_ID as REMOTE_ID, customerre0_.REMOTE_ID_TYPE as REMOTE_18_, customerre0_.REQUEST_CONTACT_CID as REQUEST19_, customerre0_.REQUEST_DATA as REQUEST20_, customerre0_.REQUEST_DESCRIPTION as REQUEST21_, customerre0_.REQUEST_STATUS as REQUEST22_, customerre0_.REQUEST_TYPE as REQUEST23_, customerre0_.REQUEST_VALUE as REQUEST24_, customerre0_.SALES_UID as SALES_UID from CUSTOMER_REQUEST customerre0_ where ((customerre0_.CR_ID=? ))
Hibernate: select customerre0_.CR_ID as CR_ID, customerre0_.ACTUAL_VALUE as ACTUAL_V2_, customerre0_.ADDITIONAL_INFO as ADDITION3_, customerre0_.ASSIGNED_AID as ASSIGNED4_, customerre0_.ASSIGNED_GID as ASSIGNED5_, customerre0_.ASSIGNED_UID as ASSIGNED6_, customerre0_.CR_AUX_ID as CR_AUX_ID, customerre0_.CREATION_DATE as CREATION8_, customerre0_.CURRENT_MILESTONE as CURRENT_9_, customerre0_.CURRENT_MILESTONE_DATE as CURRENT10_, customerre0_.FILE_ID as FILE_ID, customerre0_.MODIFICATION_DATE as MODIFIC12_, customerre0_.ORIGINATING_UID as ORIGINA13_, customerre0_.OWNER_AID as OWNER_AID, customerre0_.OWNER_GID as OWNER_GID, customerre0_.RECORD_STATE as RECORD_16_, customerre0_.REMOTE_ID as REMOTE_ID, customerre0_.REMOTE_ID_TYPE as REMOTE_18_, customerre0_.REQUEST_CONTACT_CID as REQUEST19_, customerre0_.REQUEST_DATA as REQUEST20_, customerre0_.REQUEST_DESCRIPTION as REQUEST21_, customerre0_.REQUEST_STATUS as REQUEST22_, customerre0_.REQUEST_TYPE as REQUEST23_, customerre0_.REQUEST_VALUE as REQUEST24_, customerre0_.SALES_UID as SALES_UID from CUSTOMER_REQUEST customerre0_ where ((customerre0_.CR_ID=? ))

<Fri Mar 11 08:03:31 EST 2005> <Debug > <rmine.test.Test> <calling getElementCount...>

08:03:31,579 DEBUG SQL:230 - select elements0_.CR_ID as CR_ID__, elements0_.SEQUENCE as SEQUENCE__, elements0_.CR_ID as CR_ID0_, elements0_.SEQUENCE as SEQUENCE0_, elements0_.ELEMENT_TYPE as ELEMENT_3_0_, elements0_.REQUEST_ELEMENT_DATA as REQUEST_4_0_ from CUSTOMER_REQUEST_ELEMENT elements0_ where elements0_.CR_ID=?
Hibernate: select elements0_.CR_ID as CR_ID__, elements0_.SEQUENCE as SEQUENCE__, elements0_.CR_ID as CR_ID0_, elements0_.SEQUENCE as SEQUENCE0_, elements0_.ELEMENT_TYPE as ELEMENT_3_0_, elements0_.REQUEST_ELEMENT_DATA as REQUEST_4_0_ from CUSTOMER_REQUEST_ELEMENT elements0_ where elements0_.CR_ID=?

08:03:31,599 DEBUG SQL:230 - select customerre0_.CR_ID as CR_ID0_, customerre0_.SEQUENCE as SEQUENCE0_, customerre0_.ELEMENT_TYPE as ELEMENT_3_0_, customerre0_.REQUEST_ELEMENT_DATA as REQUEST_4_0_ from CUSTOMER_REQUEST_ELEMENT customerre0_ where customerre0_.CR_ID=? and customerre0_.SEQUENCE=?
Hibernate: select customerre0_.CR_ID as CR_ID0_, customerre0_.SEQUENCE as SEQUENCE0_, customerre0_.ELEMENT_TYPE as ELEMENT_3_0_, customerre0_.REQUEST_ELEMENT_DATA as REQUEST_4_0_ from CUSTOMER_REQUEST_ELEMENT customerre0_ where customerre0_.CR_ID=? and customerre0_.SEQUENCE=?

08:03:31,669 DEBUG SQL:230 - select customerre0_.CR_ID as CR_ID0_, customerre0_.SEQUENCE as SEQUENCE0_, customerre0_.ELEMENT_TYPE as ELEMENT_3_0_, customerre0_.REQUEST_ELEMENT_DATA as REQUEST_4_0_ from CUSTOMER_REQUEST_ELEMENT customerre0_ where customerre0_.CR_ID=? and customerre0_.SEQUENCE=?
Hibernate: select customerre0_.CR_ID as CR_ID0_, customerre0_.SEQUENCE as SEQUENCE0_, customerre0_.ELEMENT_TYPE as ELEMENT_3_0_, customerre0_.REQUEST_ELEMENT_DATA as REQUEST_4_0_ from CUSTOMER_REQUEST_ELEMENT customerre0_ where customerre0_.CR_ID=? and customerre0_.SEQUENCE=?

08:03:31,689 DEBUG SQL:230 - select customerre0_.CR_ID as CR_ID0_, customerre0_.SEQUENCE as SEQUENCE0_, customerre0_.ELEMENT_TYPE as ELEMENT_3_0_, customerre0_.REQUEST_ELEMENT_DATA as REQUEST_4_0_ from CUSTOMER_REQUEST_ELEMENT customerre0_ where customerre0_.CR_ID=? and customerre0_.SEQUENCE=?
Hibernate: select customerre0_.CR_ID as CR_ID0_, customerre0_.SEQUENCE as SEQUENCE0_, customerre0_.ELEMENT_TYPE as ELEMENT_3_0_, customerre0_.REQUEST_ELEMENT_DATA as REQUEST_4_0_ from CUSTOMER_REQUEST_ELEMENT customerre0_ where customerre0_.CR_ID=? and customerre0_.SEQUENCE=?

<Fri Mar 11 08:03:31 EST 2005> <Debug > <rmine.test.Test> <Number of elements: 3>


Debug level Hibernate log excerpt:

Code:


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 11, 2005 12:53 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
batch-size


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 11, 2005 1:23 pm 
Newbie

Joined: Fri Mar 11, 2005 9:37 am
Posts: 2
I originally didn't have batch-size on the "elements" 1-M mapping and, when I saw the N+1 queries, I added batch-size="100", which you can see in my mapping, and I still get the N+1 query behavior you see here. Thank you in advance for your help.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 11, 2005 1:27 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
implement equals/hashCode correctly


Top
 Profile  
 
 Post subject: Any luck in solving this problem?
PostPosted: Thu May 12, 2005 4:04 pm 
Newbie

Joined: Fri Apr 22, 2005 10:40 am
Posts: 9
What may be wrong in the equals/hashcode ours was generated by middlegen...

In which side of the relation should I correct it?

Thanks


Top
 Profile  
 
 Post subject: Any luck in solving this problem?
PostPosted: Thu May 12, 2005 4:08 pm 
Newbie

Joined: Fri Apr 22, 2005 10:40 am
Posts: 9
What may be wrong in the equals/hashcode ours was generated by middlegen...

In which side of the relation should I correct it?

Thanks


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