-->
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: Improving performance of a hibernate one->many query
PostPosted: Fri Sep 03, 2004 4:19 am 
Newbie

Joined: Fri Sep 03, 2004 3:41 am
Posts: 3
Hello,

This is not so much a question about "how to get something working", since the code does work, rather Im trying to optimize it.

The situation is as follows: I'm performing one query, to get a list of AnalyticResult objects. Each result object will have one or more values, which are currently modelled as a one-to-many from AnalyticResult to AnalyticResultValue.

During processing of each result, I get the values, perform some aggregation, and return something else to the caller. Simple enough.

With current data, I'm getting 300 results, and in total, 17000 odd AnalyticResultVales. And each iteration of a Result causes (as expected, since the relationship is lazy) an additional SQL stmt to be executed, to get the values for the result in question.

What Im wondering is this: Assuming I don't change the schema, is there a way to speed up this access?

I tried preloading the AnalyticResultValues by performing a query that I know would return all values required during the calc/aggregation of the 300 AnalyticResult object, but of course, this doesn't work because the values association is not populated, so Hibernate makes the call to the DB in any case to figure out the content for that association.

Oh, current performance, of the two queries, is something like this:
Time to get all RESULT VALUES: 1860
Time to GET all RESULTS: 312

The first is getting the 17500 odd value objects, in a single query.
The next is getting the 300 AnalyticResult objecs.

If I allow hibernate to perform 300 selects against the value table, the total time of the query is:
Time to iterate through all RESULTS and VALUES: 6328 (iteration of result objects, calling result.getValues().iterator();

What I am wondering, is if there is anyway (apart from restructing the way my data is stored) to speed this process up.

Regards,
Neil Clayton

Hibernate version: 2.1.2
Mapping documents:
Result:
Code:
<?xml version="1.0"?>
<hibernate-mapping>
  <class name="com.xxx.AnalyticResult" table="AnalyticResult" dynamic-update="true" optimistic-lock="version" lazy="true">
    <id name="id" column="ResultId" access="field" type="long" unsaved-value="0">
           <generator class="net.sf.hibernate.id.TableHiLoGenerator">
                   <param name="table">AnalyticResultId</param>
                   <param name="column">NextId</param>
                   <param name="max_lo">20</param>    
           </generator>
    </id>
   
    <version name="version" column="Version" access="field" type="long"/>   
      <component name="key">
         <property name="book" column="Book" access="field"/>
         <property name="productType" column="ProductType" access="field"/>
         <property name="ccy" column="Currency" access="field"/>
         <property name="validated" column="Validated" access="field"/>
         <property name="tradeId" column="TradeId" access="field"/>
         <property name="referenceEntity" column="ReferenceEntity" access="field"/>
         <property name="riskyCurve" column="RiskyCurve" access="field"/>
         <property name="curveVersion" column="CurveVersion" access="field"/>
      </component>
         
    <bag name="values" cascade="all-delete-orphan" inverse="true" access="field" lazy="true">
       <cache usage="read-write"/>
      <key column="ResultId"/>
      <one-to-many class="com.xxxAnalyticResultValue"/>     
    </bag>
  </class>
</hibernate-mapping>


And ResultValue:
Code:
<hibernate-mapping>
  <class name="com.xxx.AnalyticResultValue" table="AnalyticResultValue" dynamic-update="true" optimistic-lock="version">
    <id name="id" column="ResultValueId" access="field" type="long" unsaved-value="0">
           <generator class="net.sf.hibernate.id.TableHiLoGenerator">
                   <param name="table">AnalyticResultValueId</param>
                   <param name="column">NextId</param>
                   <param name="max_lo">20</param>    
           </generator>
    </id>
   
    <version name="version" column="Version" access="field" type="long"/>
   
      <property name="typeCode" column="AnalyticType" access="property"/>
      <property name="tenor" column="Tenor" access="field"/>
      <property name="value" column="Value" access="field"/>
      
    <many-to-one name="result" column="ResultId" access="field" cascade="all" not-null="true"/>      
  </class>
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():
Full stack trace of any exception that occurs:
Name and version of the database you are using:
Sybase
Debug level Hibernate log excerpt:


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 03, 2004 4:21 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
LEFT JOIN FECH in HQL


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 06, 2004 9:52 am 
Newbie

Joined: Fri Sep 03, 2004 3:41 am
Posts: 3
Thank you. This certainly seems to produce the SQL I'm lookin for, in that it lists the result value objects that I am actually after.

However; I observe the following (this is using a subset of the previous query):

* I have 300 AnalyticResults
* There are a total of 1900 AnalyticResultValue objects, for those AnalyticResult instances

Example:
Code:
List results = session.find("from AnalyticResult r left join fetch r.values where r.key.book = 'CM_EXCREDBASKET'");
//      List results = session.find("from AnalyticResult r where r.key.book = 'CM_EXCREDBASKET'");

      startTime = System.currentTimeMillis();
      int totalValues = 0;
      for (Iterator iter = results.iterator(); iter.hasNext();) {
         AnalyticResult result = (AnalyticResult)iter.next();
         totalValues += result.getValues().size();
      }
      System.out.println("Time to iterate through all RESULTS (" + results.size() + ") and VALUES (" + totalValues + "): " + (System.currentTimeMillis() - startTime));


The results for the code, as above (using the fetch join):
Code:
Time to iterate through all RESULTS (1900) and VALUES (12400): 15


And if executed without the left join fetch:
Code:
Time to iterate through all RESULTS (300) and VALUES (1900): 11766


(ignore the timings on these, that's not what Im interested in right at the minute ;-)

If I use a left join fetch, I get back 1900 AnalyticResult instances, each of which has 5-10 AnalyticResultValue objects. It looks as though Hibernate is creating a AnalyticResult for every 'value' object returned.

Is this intentional on the part of Hibernate?

Regards,
Neil Clayton


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 06, 2004 9:58 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
yes, intentional, this is a faq


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 06, 2004 10:39 am 
Newbie

Joined: Fri Sep 03, 2004 3:41 am
Posts: 3
Thank you again, I have found the FAQ:

http://www.hibernate.org/117.html#A11

(posted for the benefit of others)


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.