-->
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.  [ 4 posts ] 
Author Message
 Post subject: Hibernate eagerly fetching data that should be lazily loaded
PostPosted: Wed Aug 04, 2004 6:03 am 
Newbie

Joined: Fri Jul 30, 2004 11:04 am
Posts: 1
Hi All,

Hibernate looks like it is generating unnecessary queries that are significantly lowering our application's performance and seem to be causing deadlocks. Of course, since we are Hibernate beginners it is probably our fault. At any rate, we are using Hibernate 2.0.3 against MS SQL Server 2000.

The problem is:
We have the following table in our database:

IF_TASKS
--------
PK | ID
FK1| JOB_ID (table IF_JOBS)
FK2| PARENT (table IF_TASKS)
FK3| TYPE_ID (table IF_TASK_TYPES)
.../other column names removed for readability/

This is HQL that we are using to query data from the IF_TASKS table:
Code:
            "select t from TaskDTO as t "
              + "where t.job.id = ? and t.type.id = ? and "
              + "((t.taskInfo.state & ?) > 0)",


Of course, t.job.id = JOB_ID and t.type.id = TYPE_ID

Hibernate generates the following queries:
1) select taskdto0_.ID as ID, .../other column names removed for readability/
from IF_TASKS taskdto0_
where (taskdto0_.JOB_ID=? )and(((taskdto0_.STATE&?)>0 ))and(taskdto0_.TYPE_ID=? )

This is cool, because it finds what we are querying for.

2) select tasktype0_.ID as ID, .../other column names removed for readability/
from IF_TASK_TYPES tasktype0_
where tasktype0_.ID=?

As far as we can see, this is unnecessary, because we only need task_type id which is in the same table.

And in case of job id there is no query! Here is an extract form hbm.xml:
Code:
    <many-to-one name="job" column="JOB_ID" not-null="true"/>
    <many-to-one name="type" column="TYPE_ID" not-null="true"/>


So why is job not queried while type is queried? They are configured the same way in our mapping file.

3) select if_tasks0_.ID as ID__, ..../other column names removed for readability/
from IF_TASKS if_tasks0_
where if_tasks0_.PARENT=?

This is also not need at this stage, this db query sets subtasks,
but subtasks shouldn't be set immediately as it is set to load lazy:
Code:
    <set name="subtasks" lazy="true" inverse="true" cascade="all">
      <key column="PARENT"/>
      <one-to-many class="com.abb.sf.iff.data.orders.TaskDTO"/>
    </set>


We have other Sets defined this way which are not queried, for example:
Code:
    <set name="materials" lazy="true" inverse="true" cascade="all">
      <key column="TASK_ID"/>
      <one-to-many class="com.abb.sf.iff.data.orders.TaskMaterialDTO"/>
    </set>


So 'subtasks' Set is unneccesarily initialized but other Sets are not initialized (this is correct). All sets are configured the same way in our mapping file.

Here is our mapping file:

Code:
<hibernate-mapping>
  <class name="com.abb.sf.iff.data.orders.TaskDTO" table="IF_TASKS" proxy="com.abb.sf.iff.data.orders.TaskDTO">
    <id name="id" column="ID" unsaved-value="null">
      <generator class="identity"/>
    </id>
    <many-to-one name="job" column="JOB_ID" not-null="true"/>
    <many-to-one name="type" column="TYPE_ID" not-null="true"/>
    <many-to-one name="parentTask" column="PARENT" outer-join="false"/>
    <component name="taskInfo" class="com.abb.sf.iff.data.orders.TaskInfoDTO" insert="true" update="true">
      <property name="erpId" column="ERP_ID" type="java.lang.String" update="true" insert="true"/>
      <property name="description" column="DESCRIPTION" type="java.lang.String" update="true" insert="true"/>
      <property name="plannedStartDate" column="PLANNED_START_DATE" type="java.util.Date" update="true" insert="true"/>
      <property name="plannedFinishDate" column="PLANNED_FINISH_DATE" type="java.util.Date" update="true" insert="true"/>
      <property name="actualStartDate" column="ACTUAL_START_DATE" type="java.util.Date" update="true" insert="true"/>
      <property name="actualFinishDate" column="ACTUAL_FINISH_DATE" type="java.util.Date" update="true" insert="true"/>
      <property name="batchQuantity" column="BATCH_QUANTITY" type="java.lang.Integer" update="true" insert="true"/>
      <property name="state" column="STATE" type="java.lang.Integer" update="true" insert="true"/>
      <property name="mesMilestone" column="MES_MILESTONE" type="java.lang.Boolean" update="true" insert="true"/>
      <property name="mspMilestone" column="MSP_MILESTONE" type="java.lang.Boolean" update="true" insert="true"/>
      <property name="erpMilestone" column="ERP_MILESTONE" type="java.lang.Boolean" update="true" insert="true"/>
      <property name="summary" column="SUMMARY" type="java.lang.Boolean" update="true" insert="true"/>
    </component>
    <property name="ifActions" column="IF_ACTIONS" type="java.lang.Integer" update="true" insert="true"/>
    <property name="lastUpdateTS" column="LAST_UPDATE_TS" type="java.util.Date" update="true" insert="true"/>
    <property name="materialsUpdateTS" column="MATERIALS_UPDATE_TS" type="java.util.Date" update="true" insert="true"/>
   
    <set name="subtasks" lazy="true" inverse="true" cascade="all">
      <key column="PARENT"/>
      <one-to-many class="com.abb.sf.iff.data.orders.TaskDTO"/>
    </set>

    <set name="materials" lazy="true" inverse="true" cascade="all">
      <key column="TASK_ID"/>
      <one-to-many class="com.abb.sf.iff.data.orders.TaskMaterialDTO"/>
    </set>
    <set name="assignments" lazy="true" inverse="true" cascade="all">
      <key column="TASK_ID"/>
      <one-to-many class="com.abb.sf.iff.data.orders.AssignmentDTO"/>
    </set>
    <set name="extensions" lazy="true" inverse="false" cascade="all">
      <key column="TASK_ID"/>
      <one-to-many class="com.abb.sf.iff.data.orders.TaskPropertyDTO"/>
   </set>
   <set name="components" table="IF_TASK_COMPONENT" lazy="true" cascade="all">
     <key column="TASK_ID"/>
     <many-to-many class="com.abb.sf.iff.data.components.ComponentDTO" column="COMPONENT_ID"/>
   </set>
   <set name="confirmations" table="IF_ERP_CONFIRMATIONS" lazy="true" inverse="true" cascade="all">
     <key column="TASK_ID"/>
     <one-to-many class="com.abb.sf.iff.data.orders.ConfirmationDTO"/>
   </set>
  </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 04, 2004 10:01 am 
Expert
Expert

Joined: Fri Feb 06, 2004 7:49 am
Posts: 255
Location: Moscow, Russia
If you want eager fetching use JOIN FETCH:
Code:
select t from TaskDTO t
    inner join fetch t.job job
    inner join fetch t.type type
    inner join fetch t.taskInfo
where job.id = ? and type.id = ? and ((taskInfo.state & ?) > 0)

or use Criteria.setFetchMode("job", FetchMode.EAGER) and etc

--
Leonid


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 06, 2004 9:10 am 
Newbie

Joined: Fri Aug 06, 2004 8:42 am
Posts: 1
Hi Leonid,
Thank you for replying so quickly.
I am working together with jgoodling on solving this issue.
We heave a little misunderstanding here, we don't want to fetch this data as this results in additional joins in SQL query or additional SQL-queries. And we don't need this data.

Our application is working 24/7 and we are fighting with db performance problems, this is why we need to reduce unnecessary db connections/queries and optimize those, which are necessary (for example by keeping joins number minimal).

Our problem is that we have 2 unnecessary SQL queries for each 'task', when querying TaskDTO:

Code:
select tasktype0_.ID ...
(for task-type)
and
Code:
select if_tasks0_.ID ...
(for subtasks)

When "select t from TaskDTO ..." returns many tasks the number of unnecessary queries is 2 x returned_taskDTO.

The partial workaround for this problem that I've found is similar to the one you posted:

Code:
            select t from TaskDTO as t
               inner join fetch t.type
               left outer join fetch t.subtasks
                  where t.job.id = ? and t.type.id = ? and
                  ((t.taskInfo.state & ?) > 0)


Using this, we have one SQL-query generated, but it contains two joins, and we don't need that data.
So our question is: How to tell Hibernate not to fetch the data that we don't need (subtasks and task-type) ?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 06, 2004 10:21 am 
Expert
Expert

Joined: Fri Feb 06, 2004 7:49 am
Posts: 255
Location: Moscow, Russia
As I understand you have done everything to say hibernate to use lazy initialization. But check if class of "type" association proxied, or mapped as lazy="true".

"subtasks"....
Quote:
We have other Sets defined this way which are not queried

"substasks" differs from all other collections by its elements, it contains other tasks, I don't know what to do, but try to map your TaskDTO with lazy="true" instead of proxy, I am not sure, but possibly it is a hibernate bug.

--
Leonid


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