Jun 22 2008

Hibernate Query Performance Logging

Tag:Tag , alvinsingh @ 22:48

One critical feature missing in Hibernate is the ability to log how long queries are taking. This is vital when you are performance tuning your application to see which parts can be optimized and also can highlight issues with the database (missing indexes, fragmentation etc.). With the correct fetching and batch strategies you usually don’t have to do too much, but it is always good to know how long things are taking. It can help in defining the order in which queries should run and even identify that maybe you should be doing queries in parallel.

There are configuration options already which allow you to print the sql queries being run but nothing I have seen which allows me to do the above. btw. if anybody knows how to print the full sql query with the parameters I would love to know.

One can always write logging statements surrounding each method (usually DAO methods) running the queries, however this is quite pervasive. It would be nicer to do and change as little as possible and get query execution times. Aspect-oriented programming can help us here. The following piece is an example using Spring+Hibernate stack since this is what I use - and it makes it so easy!

For a full description on AOP head-over to wikipedia linked above - I will give a very short crash-course. The idea behind AOP is the separation of concerns. We have packages, classes and methods which assist us with separation and modularization. Some concerns though don’t fit into this idea - they ‘crosscut’ other concerns. An example is logging. Aspect oriented programming gives us additional tools by which we can separate these sorts of ‘concerns’.

So firstly the code -


package au.com.xyz.aop;

import org.apache.commons.lang.time.StopWatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class DAOInterceptor {

            protected Log log = LogFactory.getLog(DAOInterceptor.class);

            @Around("execution(* au.com.xyz.dao..*.*(..))")
            public Object logHibernateQueryTimes(ProceedingJoinPoint pjp) throws Throwable {
                        StopWatch stopWatch = new StopWatch();
                        stopWatch.start();
                        Object retVal = pjp.proceed();
                        stopWatch.stop();

                        String str = pjp.getTarget().toString();
                        log.debug(str.substring(str.lastIndexOf(".")+1, str.lastIndexOf("@")) + " - " + pjp.getSignature().getName() + ": " + stopWatch.getTime() + "ms");
                        return retVal;
            }

}

The AOP class is a simple POJO with some annotations -

  • @Component is Spring related - so Spring will create an instance of the bean when it scans.
  • @Aspect declares that this class is an Aspect
  • @Around is Aspect related - means that execute this method around the methods in the classes given by expression (i.e. before the actual method is called and after the method is called)

In the actual method you can see it is again very simple -

  • Lines 19-20: I start a timer (commons StopWatch)
  • Line 21: Invoke the DAO method which will run the query and keep the return value
  • Line 22: Stop the timer
  • Line 24-25: Log the time taken for the query
  • Line 26: Return the value of the DAO method

The only other thing left to do is to configure Spring to enable AOP.


<beans xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/aop
       					   http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

	<aop:aspectj-autoproxy />
</beans>

That’s it! Depending on how you’ve configured your logging, you should see output similar to the following in your log -

[sourcecode language='bash']
17:51:48,411 DEBUG au.com.xyz.aop.DAOInterceptor - CountryDAO - findAllCountries - 20ms
17:51:48,435 DEBUG au.com.xyz.aop.DAOInterceptor - CountryDAO - findCountriesStartingWith - 34ms
[/sourcecode]
BlogMemes del.icio.us Digg DZone Facebook FeedMeLinks Google Google Reader Ask.com Yahoo! MyWeb Newsvine reddit Simpy SlashDot StumbleUpon Technorati

6 risposte a “Hibernate Query Performance Logging”

  1. Database Management » Blog Archive » Hibernate Query Performance Logging ha scritto:

    [...] Technorati Search for: databases wrote an interesting post today onHere’s a quick excerpt One critical feature missing in Hibernate is the ability to log how long queries are taking. This is vital when you are performance tuning your application to see which parts can be optimized and also can highlight issues with the databases (missing indexes, fragmentation etc.). With the correct fetching and batch strategies you usually don’t have to do too much, but it is always good to know how long things are taking. It can help in defining the order in which queries should run and even iden [...]

  2. david ha scritto:

    You can turn on logging your statements if you switch “org.hibernate.type” to DEBUG logging in your log4j config. However, it’s very verbose and IMHO not really helpful.

  3. alvinsingh ha scritto:

    David: This doesn’t actually show the sql with the arguements (i.e. so I can copy and paste into sql server and run).

  4. William Louth ha scritto:

    You can do this with JXInsight and have actual transaction history pattern analysis and aggregated statistics along with timeline analysis for concurrency issues. We also have a probes solution for production environments as the above code is measuring more than just the database here.

    William

  5. alvinsingh ha scritto:

    JXInsight looks pretty heavy duty - will have to look into it. You are right in that the code is measuring more than just the database - there will be a very small amount of time taken to grab a session, construct the query etc, however this should be insignificant in comparison to the time taken for the query. Of course, if you need true query performance stats you would have to look on the database itself.

  6. Cialisei ha scritto:

    Nice Blog. Good Look

Leave a Reply